1.简单工厂模式:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。它通过建立一个单独的类来做这个创造实例的过程,这就是工厂。
简单工厂模式的结构如下图:
以加减乘除运算类为例:
1 /** 2 * 抽象运算类 3 */ 4 public interface Operation { 5 double getResult(double a, double b); 6 }
1 /** 2 *加法运算,具体运算类 3 */ 4 public class Add implements Operation{ 5 @Override 6 public double getResult(double a, double b){ 7 return a+b; 8 } 9 }
1 /** 2 * 减法运算,具体运算类 3 */ 4 public class Substract implements Operation { 5 @Override 6 public double getResult(double a, double b){ 7 return a-b; 8 } 9 }
1 /** 2 * 乘法运算,具体运算类 3 */ 4 public class Multiply implements Operation { 5 6 @Override 7 public double getResult(double a, double b){ 8 return a*b; 9 } 10 }
1 /** 2 * 除法运算,具体运算类 3 */ 4 public class Divide implements Operation { 5 @Override 6 public double getResult(double a, double b){ 7 return a/b; 8 } 9 }
1 package com.alice.simpleFactory; 2 3 /** 4 * 简单工厂模式,里面根据不同的运算符实例化不同的运算对象 5 */ 6 public class SimpleFactory { 7 public Operation createOperation(String type){ 8 Operation operation = null ; 9 switch (type){ 10 case "+": 11 operation = new Add(); 12 break; 13 case "-": 14 operation = new Substract(); 15 break; 16 case "*": 17 operation = new Multiply(); 18 break; 19 case "/" : 20 operation = new Divide(); 21 break; 22 } 23 return operation; 24 } 25 }
1 package com.alice.simpleFactory; 2 3 public class Client { 4 5 public static void main(String[] args){ 6 SimpleFactory factory = new SimpleFactory(); 7 Operation operation = factory.createOperation("+");//免除了new Add()实例化 8 double result = operation.getResult(1,2); 9 System.out.println(result); 10 } 11 }
这几个类的结构图如下:
简单工厂优点:
模式的核心是工厂类。这个类含有必要的逻辑判断,可以决定在什么时候创建哪一个运算类的实例,而调用者则可以免除直接创建对象的责任。简单工厂模式通过这种做法实现了对责任的分割,当系统引入新的运算符的时候无需修改调用者。
简单工厂的缺点:
这个工厂类集中了所以的创建逻辑,当有复杂的多层次等级结构时,所有的业务逻辑都在这个工厂类中实现。什么时候它不能工作了,整个系统都会受到影响。
2.工厂模式:工厂方法模式是类的创建模式,又叫做虚拟构造子(Virtual Constructor)模式或者多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
相比于简单工厂的分类图,工厂模式类图如下所示:
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Operation; 4 5 public interface Factory { 6 Operation createOperation(); 7 }
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Add; 4 import com.alice.simpleFactory.Operation; 5 6 public class AddFactory implements Factory { 7 @Override 8 public Operation createOperation(){ 9 return new Add(); 10 } 11 }
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Operation; 4 import com.alice.simpleFactory.Substract; 5 6 public class SubstractFactory implements Factory { 7 @Override 8 public Operation createOperation() { 9 return new Substract(); 10 } 11 }
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Multiply; 4 import com.alice.simpleFactory.Operation; 5 6 public class MultiplyFactory implements Factory { 7 @Override 8 public Operation createOperation() { 9 return new Multiply(); 10 } 11 }
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Divide; 4 import com.alice.simpleFactory.Operation; 5 6 public class DivideFactory implements Factory { 7 @Override 8 public Operation createOperation() { 9 return new Divide(); 10 } 11 }
1 package com.alice.factory; 2 3 import com.alice.simpleFactory.Operation; 4 5 public class Client { 6 public static void main(String[] args){ 7 Factory add = new AddFactory(); 8 Operation operation = add.createOperation(); 9 double result = operation.getResult(1.2, 3.5); 10 System.out.println(result); 11 12 13 } 14 }
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端而言,去除了与具体产品的依赖。
工厂模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。若想要增加功能,本来是要修改工厂类的,而现在需要修改客户端。
3.抽象工厂模式:
抽象工厂模式提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体的类。抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则需要面对多个产品等级结构。
在学习抽象工厂具体实例之前,应该明白两个重要的概念:产品族和产品等级。
所谓产品族,是指位于不同产品等级结构中,功能相关联的产品组成的家族。比如AMD的主板、芯片组、CPU组成一个家族,Intel的主板、芯片组、CPU组成一个家族。而这两个家族都来自于三个产品等级:主板、芯片组、CPU。一个等级结构是由相同的结构的产品组成,示意图如下:
显然,每一个产品族中含有产品的数目,与产品等级结构的数目是相等的。产品的等级结构与产品族将产品按照不同方向划分,形成一个二维的坐标系。横轴表示产品的等级结构,纵轴表示产品族,上图共有两个产品族,分布于三个不同的产品等级结构中。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一的确定这个产品。
上面所给出的三个不同的等级结构具有平行的结构。因此,如果采用工厂方法模式,就势必要使用三个独立的工厂等级结构来对付这三个产品等级结构。由于这三个产品等级结构的相似性,会导致三个平行的工厂等级结构。随着产品等级结构的数目的增加,工厂方法模式所给出的工厂等级结构的数目也会随之增加。如下图:
那么,是否可以使用同一个工厂等级结构来对付这些相同或者极为相似的产品等级结构呢?当然可以的,而且这就是抽象工厂模式的好处。同一个工厂等级结构负责三个不同产品等级结构中的产品对象的创建。
可以看出,一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。显然,这时候抽象工厂模式比简单工厂模式、工厂方法模式更有效率。对应于每一个产品族都有一个具体工厂。而每一个具体工厂负责创建属于同一个产品族,但是分属于不同等级结构的产品。
抽象工厂模式结构
抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。
假设一个子系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。那么为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。这样的话,消费产品的一方不需要直接参与产品的创建工作,而只需要向一个公用的工厂接口请求所需要的产品。
通过使用抽象工厂模式,可以处理具有相同(或者相似)等级结构中的多个产品族中的产品对象的创建问题。如下图所示:
由于这两个产品族的等级结构相同,因此使用同一个工厂族也可以处理这两个产品族的创建问题,这就是抽象工厂模式。
根据产品角色的结构图,就不难给出工厂角色的结构设计图。
可以看出,每一个工厂角色都有两个工厂方法,分别负责创建分属不同产品等级结构的产品对象。
源代码
前面示例实现的CPU接口和CPU实现对象,主板接口和主板实现对象,都不需要变化。
前面示例中创建CPU的简单工厂和创建主板的简单工厂,都不再需要。
新加入的抽象工厂类和实现类:
1 public interface AbstractFactory { 2 /** 3 * 创建CPU对象 4 * @return CPU对象 5 */ 6 public Cpu createCpu(); 7 /** 8 * 创建主板对象 9 * @return 主板对象 10 */ 11 public Mainboard createMainboard(); 12 }
1 public class IntelFactory implements AbstractFactory { 2 3 @Override 4 public Cpu createCpu() { 5 // TODO Auto-generated method stub 6 return new IntelCpu(755); 7 } 8 9 @Override 10 public Mainboard createMainboard() { 11 // TODO Auto-generated method stub 12 return new IntelMainboard(755); 13 } 14 15 }
1 public class AmdFactory implements AbstractFactory { 2 3 @Override 4 public Cpu createCpu() { 5 // TODO Auto-generated method stub 6 return new IntelCpu(938); 7 } 8 9 @Override 10 public Mainboard createMainboard() { 11 // TODO Auto-generated method stub 12 return new IntelMainboard(938); 13 } 14 15 }
装机工程师类跟前面的实现相比,主要的变化是:从客户端不再传入选择CPU和主板的参数,而是直接传入客户已经选择好的产品对象。这样就避免了单独去选择CPU和主板所带来的兼容性问题,客户要选就是一套,就是一个系列。
1 public class ComputerEngineer { 2 /** 3 * 定义组装机需要的CPU 4 */ 5 private Cpu cpu = null; 6 /** 7 * 定义组装机需要的主板 8 */ 9 private Mainboard mainboard = null; 10 public void makeComputer(AbstractFactory af){ 11 /** 12 * 组装机器的基本步骤 13 */ 14 //1:首先准备好装机所需要的配件 15 prepareHardwares(af); 16 //2:组装机器 17 //3:测试机器 18 //4:交付客户 19 } 20 private void prepareHardwares(AbstractFactory af){ 21 //这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个 22 //可是,装机工程师并不知道如何去创建,怎么办呢? 23 24 //直接找相应的工厂获取 25 this.cpu = af.createCpu(); 26 this.mainboard = af.createMainboard(); 27 28 //测试配件是否好用 29 this.cpu.calculate(); 30 this.mainboard.installCPU(); 31 } 32 }
客户端代码:
1 public class Client { 2 public static void main(String[]args){ 3 //创建装机工程师对象 4 ComputerEngineer cf = new ComputerEngineer(); 5 //客户选择并创建需要使用的产品对象 6 AbstractFactory af = new IntelFactory(); 7 //告诉装机工程师自己选择的产品,让装机工程师组装电脑 8 cf.makeComputer(af); 9 } 10 }
抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口。一定要注意,这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法。比如上面例子中的主板和CPU,都是为了组装一台电脑的相关对象。不同的装机方案,代表一种具体的电脑系列。
由于抽象工厂定义的一系列对象通常是相关或相互依赖的,这些产品对象就构成了一个产品族,也就是抽象工厂定义了一个产品族。
这就带来非常大的灵活性,切换产品族的时候,只要提供不同的抽象工厂实现就可以了,也就是说现在是以一个产品族作为一个整体被切换。
在什么情况下应当使用抽象工厂模式
1.一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2.这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
3.同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。(比如:Intel主板必须使用Intel CPU、Intel芯片组)
4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
抽象工厂模式的起源
抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(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产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:
显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。
在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。因此,可以不必理会前面所提到的原始用意。
抽象工厂模式的优点
- 分离接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
- 使切换产品族变得容易
因为一个具体的工厂实现代表的是一个产品族,比如上面例子的从Intel系列到AMD系列只需要切换一下具体工厂。
抽象工厂模式的缺点
- 不太容易扩展新的产品
如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。
另外还可以利用反射+抽象工厂模式或者配置文件+抽象工厂模式的方式解决上述问题。
a.反射+抽象工厂模式:
b.配置文件+抽象工厂模式:
参考https://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html