工厂模式是JAVA中
最常用的设计模式之一
,使用工厂模式后,创建对象的时候不在将创建逻辑暴露给客户端,而是通过实现接口的方式创建对象,这种设计模式也是对象实例化的最佳方式。
<!-- more -->
概述
工厂模式的三种形态
- 简单工厂(Simple Factory)
- 工厂方法(Factory Method)
- 抽象工厂(Abstract Factory)
简单工厂
简单工厂模式属于工厂模式的小弟
,未被收纳进GOF 23
中,但是也被频繁使用
1.创建一个Animal
接口
interface Shape {
void draw();
}
2.创建Dog
和Pig
实现Animal
接口
class Circle implements Shape {
public Circle() {
System.out.println("创建圆形模型");
}
@Override
public void draw() {
System.out.println("画了一个圆形");
}
}
class Square implements Shape {
public Square() {
System.out.println("创建了方形模型");
}
@Override
public void draw() {
System.out.println("画了一个方形");
}
}
3.创建工厂类SimpleFactory
,定义一个基于参数信息实例化具体对象的方法
public class SimpleFactory {
private final static String CIRCLE = "CIRCLE";
private final static String SQUARE = "SQUARE";
public static Shape getFactory(String type) {
switch (type) {
case CIRCLE:
return new Circle();
case SQUARE:
return new Square();
default:
throw new NullPointerException("未描绘任何图形");
}
}
public static void main(String[] args) {
Shape circle = SimpleFactory.getFactory(CIRCLE);
circle.draw();
Shape square = SimpleFactory.getFactory(SQUARE);
square.draw();
}
}
4.日志
创建圆形模型
画了一个圆形
创建了方形模型
画了一个方形
分析: 从上述代码中可以发现,简单工厂
拥有一定判断能力,构建结果取决于入参,使用起来也十分的方便,也正因为使用太过方便
而导致高耦合
的情况,所有对象实例化都需要依赖它,一旦出问题,影响的会是整个系统
使用场景: 创建简单,无复杂业务逻辑的对象
工厂方法
前面说到过简单工厂模式
存在耦合,且违反了开闭原则
,那么这一问题在工厂方法模式
中可以很容易的解决掉,它可以做到添加新的产品而不破坏已有代码
工厂方法模式
:定义一个创建对象的接口,由它的实现类来决定具体实现,其模式又被称为工厂模式(Factory Pattern)
。
1.新增ImageReaderFactory
抽象工厂接口,用来构建具体的对象
interface ImageReader {
void read();
}
interface ImageReaderFactory {
ImageReader create();
}
2.相比单一实例化的简单工厂模式
而言,方法工厂模式
更加的灵活,针对不同的产品(图片读取器)
提供不同的工厂。
class JpgReader implements ImageReader {
public JpgReader() {
System.out.println("创建Jpg读取器");
}
@Override
public void read() {
System.out.println("读取Jpg文件");
}
}
class PngReader implements ImageReader {
public PngReader() {
System.out.println("创建Png读取器");
}
@Override
public void read() {
System.out.println("读取Png文件");
}
}
class JpgFactory implements ImageReaderFactory {
@Override
public ImageReader create() {
System.out.println("实例化Jpg文件工厂");
return new JpgReader();
}
}
class PngFactory implements ImageReaderFactory {
@Override
public ImageReader create() {
System.out.println("实例化Png文件工厂");
return new PngReader();
}
}
3.创建测试类,当然实际使用过程中,实现工厂方法
除了可以实例化具体对象,还可以初始化某些资源配置,比如连接池、创建文件等
public class MethodFactory {
public static void main(String[] args) {
ImageReaderFactory png = new PngFactory();
ImageReader pngReader = png.create();
pngReader.read();
ImageReaderFactory jpg = new JpgFactory();
ImageReader jpgReader = jpg.create();
jpgReader.read();
}
}
4.日志
实例化Png文件工厂
创建Png读取器
读取Png文件
实例化Jpg文件工厂
创建Jpg读取器
读取Jpg文件
优点:
- 屏蔽了客户端实例化对象的细节,用户只需要关心自己使用的工厂即可。
- 加入新的
产品(图片读取器)
,无需更改现有代码,提高系统扩展性,符合开闭原则
- 具备
多态性
,又被称为多态工厂模式
缺点: 每次需要编写新的对象和对象工厂类
,随业务发展,一定程度上增加了系统复杂度
抽象工厂
-
抽象工厂模式
是为创建一组对象提供提供的解决方案,与工厂方法模式相比
,抽象工厂模式中的具体工厂不只是创建某一种产品,而是负责一组(产品族)。 -
抽象工厂模式(Abstract Factory Pattern)
:提供了创建一系列相互依赖对象的接口,无需指定具体类 -
抽象工厂模式
是围绕着一个超级工厂工作,创造其它的工厂类,也被称为工厂的工厂
,这种类型的设计模式是创造性的模式,因为这种模式提供了创建对象的最佳方法之一。
起源
抽象工厂模式
的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。
在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。
可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构。同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UNIX Button和UNIX Text产品构成;而Windows产品族由Windows Button和Windows Text产品构成。
系统对产品对象的创建需求由一个工程的等级结构满足,其中有两个具体工程角色,即UnixFactory和WindowsFactory。UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:
显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。
在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。因此,可以不必理会前面所提到的原始用意。
摘抄自《JAVA与模式》之抽象工厂模式:http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
需求: 开发一款《王者荣耀》,支持多操作系统和多控制方式操作控制
和界面控制
,并提供相应的工厂类来封装这些类的初始化过程
1.创建不同的操作系统接口
interface Linux {
void controller();
}
interface Windows {
void controller();
}
2.基于不同操作系统实现控制逻辑
class LinuxController implements Linux {
@Override
public void controller() {
System.out.println("Linux 控制 《王者荣耀》");
}
}
class WindowsController implements Windows {
@Override
public void controller() {
System.out.println("Windows 控制 《王者荣耀》");
}
}
3.创建一个工厂类,基于接口分别实现操作控制
和界面控制
两种方式的工厂
interface AbstractFactory {
Linux installLinux();
Windows installWindows();
}
class OperationFactory implements AbstractFactory {
@Override
public Linux installLinux() {
System.out.println("安装Linux操作控制系统");
return new LinuxController();
}
@Override
public Windows installWindows() {
System.out.println("安装Windows操作控制系统");
return new WindowsController();
}
}
class InterfaceFactory implements AbstractFactory {
@Override
public Linux installLinux() {
System.out.println("安装Linux界面控制系统");
return new LinuxController();
}
@Override
public Windows installWindows() {
System.out.println("安装Windows界面控制系统");
return new WindowsController();
}
}
4.创建《王者荣耀》进行测试
public class KingGlory {
public static void main(String[] args) {
AbstractFactory operationFactory = new OperationFactory();
operationFactory.installLinux().controller();
operationFactory.installWindows().controller();
System.out.println("========================================================");
AbstractFactory interfaceFactory = new InterfaceFactory();
interfaceFactory.installLinux().controller();
interfaceFactory.installWindows().controller();
}
}
5.日志
安装Linux操作控制系统
Linux 控制 《王者荣耀》
安装Windows操作控制系统
Windows 控制 《王者荣耀》
========================================================
安装Linux界面控制系统
Linux 控制 《王者荣耀》
安装Windows界面控制系统
Windows 控制 《王者荣耀》
分析
使用抽象工厂模式
来定义的一系列对象通常是相关或相互依赖的,这些产品对象就构成了一个产品族
,也就是抽象工厂定义了一个产品族
。这就带来非常大的灵活性,切换产品族的时候,只要提供不同的抽象工厂实现就可以了,也就是说现在是以一个产品族作为一个整体被切换,从上文中可以发现,如果我们需要切换控制方式
,只需要变更下对应的工厂类即可
优点:
- 分离接口和实现:客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
- 切换产品族变得容易:对于增加新的产品族,抽象工厂模式很好地支持了
开闭原则
,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改(如:新增一种手柄操作支持)。
缺点:
- 不易扩展新产品:如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类(如:新增一种操作系统的支持,那么
Factory
代码需要全部修改)。
使用场景:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
- 这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
- 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
- 说点什么
全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter1/battcn-factory
- 个人QQ:1837307557
- battcn开源群(适合新手):391619659
微信公众号:battcn
(欢迎调戏)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。