定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
类型:对象创建型模式
类图:
抽象工厂模式示例代码
1、抽象工厂的定义,示例代码如下:
/** * 抽象工厂的接口,声明创建抽象产品对象的操作 * @author FX_SKY * */ public interface AbstractFactory { /** * 示例方法,创建抽象产品A的对象 * @return */ public AbstractProductA createProductA(); /** * 示例方法,创建抽象产品B的对象 * @return */ public AbstractProductB createProductB(); }
/** * 抽象产品A的接口 * @author FX_SKY * */ public interface AbstractProductA { //定义抽象产品A相关的操作 }
/** * 抽象产品B的接口 * @author FX_SKY * */ public interface AbstractProductB { //定义抽象产品B相关的操作 }
实现产品A示例代码如下:
/** * 产品A的具体实现 * @author FX_SKY * */ public class ProductA1 implements AbstractProductA { //实现产品A的接口中定义的操作 }
/** * 产品A的具体实现 * @author FX_SKY * */ public class ProductA2 implements AbstractProductA { //实现产品A的接口中定义的操作 }
/** * 产品B的具体实现 * @author FX_SKY * */ public class ProductB1 implements AbstractProductB { //实现产品B的接口中定义的操作 }
/** * 产品B的具体实现 * @author FX_SKY * */ public class ProductB2 implements AbstractProductB { //实现产品B的接口中定义的操作 }
/** * 具体的工厂实现对象,实现创建具体的产品对象的操作 * @author FX_SKY * */ public class ConcreteFactory1 implements AbstractFactory { @Override public AbstractProductA createProductA() { return new ProductA1(); } @Override public AbstractProductB createProductB() { return new ProductB1(); } }
/** * 具体的工厂实现对象,实现创建具体的产品对象的操作 * @author FX_SKY * */ public class ConcreteFactory2 implements AbstractFactory { @Override public AbstractProductA createProductA() { return new ProductA2(); } @Override public AbstractProductB createProductB() { return new ProductB2(); } }
public class Client { /** * @param args */ public static void main(String[] args) { //创建抽象工厂对象 AbstractFactory af = new ConcreteFactory1(); //通过抽象工厂来获取一系列的对象,如产品A和产品B af.createProductA(); af.createProductB(); } }
装机工程师要组装电脑对象,需要一系列的产品对象,比如CPU、主板等,于是创建一个抽象工厂给装机工程师使用,在这个抽象工厂里面定义抽象的创建CPU和主板的方法,这个抽象工厂就相当于一个抽象的装机方案,在这个装机方案里面,各个配件是能够相互匹配的。
每个装机的客户,会提出他们自己的具体装机方案,或者是选择已有的装机方案,相当于为抽象工厂提供了具体的子类,在这些具体的装机方案类里面,会创建具体的CPU和主板实现对象。
1、先看看CPU和主板的接口
CPU接口定义的示例代码如下:
/** * CPU的接口 * @author FX_SKY * */ public interface CPUApi { /** * 示意方法,CPU具有运算的功能 */ public void calculate(); }
主板接口定义的示例代码如下:
/** * 主板的接口 * @author FX_SKY * */ public interface MainBoardApi { /** * 示意方法,主板都具有安装CPU的功能 */ public void installCPU(); }
2、具体的CPU实现
Intel CPU实现示例代码如下:
/** * Intel 的 CPU实现 * @author FX_SKY * */ public class IntelCPU implements CPUApi { /** * CPU的针脚数目 */ private int pins = 0; /** * 构造方法,传人CPU的针脚数目 * @param pins */ public IntelCPU(int pins) { this.pins = pins; } @Override public void calculate() { System.out.println("now in Intel CPU,pins="+pins); } }AMD CPU实现示例代码如下:
/** * AMD 的 CPU实现 * @author FX_SKY * */ public class AMDCPU implements CPUApi { /** * CPU的针脚数目 */ private int pins = 0; /** * 构造方法,传人CPU的针脚数目 * @param pins */ public AMDCPU(int pins) { this.pins = pins; } @Override public void calculate() { System.out.println("now in AMD CPU,pins="+pins); } }
技嘉主板实现的示例代码如下:
/** * 技嘉主板 * @author FX_SKY * */ public class GAMainBoard implements MainBoardApi { /** * CPU插槽的孔数 */ private int cpuHoles = 0; /** * 构造方法,传人CPU插槽的孔数 * @param cpuHoles */ public GAMainBoard(int cpuHoles) { this.cpuHoles = cpuHoles; } @Override public void installCPU() { System.out.println("now in GAMainBoard,cpuHoles="+cpuHoles); } }
华硕主板实现的示例代码如下:
/** * 华硕主板 * @author FX_SKY * */ public class ASUSMainBoard implements MainBoardApi { /** * CPU插槽的孔数 */ private int cpuHoles = 0; /** * 构造方法,传人CPU插槽的孔数 * @param cpuHoles */ public ASUSMainBoard(int cpuHoles) { this.cpuHoles = cpuHoles; } @Override public void installCPU() { System.out.println("now in ASUSMainBoard,cpuHoles="+cpuHoles); } }
/** * 抽象工厂的接口,声明创建抽象产品对象的操作 * @author FX_SKY * */ public interface AbstractFactory { /** * 创建CPU的对象 * @return */ public CPUApi createCPUApi(); /** * 创建主板的对象 * @return */ public MainBoardApi createMainBoardApi(); }
方案1:的实现,示例代码如下:
/** * 装机方案1:AMD CPU + 华硕主板 * 这里创建CPU和主板对象的时候,是对应的,能匹配上的 * @author FX_SKY * */ public class Schema1 implements AbstractFactory { @Override public CPUApi createCPUApi() { return new AMDCPU(956); } @Override public MainBoardApi createMainBoardApi() { return new ASUSMainBoard(956); } }
方案2:的实现,示例代码如下:
/** * 装机方案2:Intel CPU + 技嘉主板 * 这里创建CPU和主板对象的时候,是对应的,能匹配上的 * @author FX_SKY * */ public class Schema2 implements AbstractFactory { @Override public CPUApi createCPUApi() { return new IntelCPU(1156); } @Override public MainBoardApi createMainBoardApi() { return new GAMainBoard(1156); } }
/** * 装机工程师的类 * @author FX_SKY * */ public class ComputerEngineer { /** * 定义组装电脑需要的CPU */ private CPUApi cpu; /** * 定义组装电脑需要的主板 */ private MainBoardApi mainBoard; public void makeComputer(AbstractFactory schema){ //1、首先准备好装机所需要的配件 prepareHardwares(schema); //2、组装电脑 //3、测试电脑 //4、交付客户 } private void prepareHardwares(AbstractFactory schema) { //使用抽象工厂来获取相应的接口对象 this.cpu = schema.createCPUApi(); this.mainBoard = schema.createMainBoardApi(); //测试一下配件是否好用 this.cpu.calculate(); this.mainBoard.installCPU(); } }
public class Client { /** * @param args */ public static void main(String[] args) { //创建装机工程师对象 ComputerEngineer cm = new ComputerEngineer(); //客户选择并创建需要使用的装机方案对象 Schema1 schema1 = new Schema1(); //告诉装机工程师自己的装机方案,让装机工程师组装电脑 cm.makeComputer(schema1); } }
抽象工厂模式的功能
抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口。一定要注意这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法,比如上面例子中的CPU和主板,都是为了组装一台电脑的相关对象。
从某种意义上看,抽象工厂其实是一个产品系列,或者是产品簇。上面例子中的抽象工厂就可以看成是电脑簇,每个不同的装机方案,代表一种具体的电脑系列。
抽象模式的优缺点
抽象工厂模式的优点
分离接口和实现
客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
使得切换产品簇变得容易
因为一个具体的工厂实现代表一个产品簇,比如上面例子的Schema1代表装机方案一,如果要切换到Schema2,那就变成了装机方案二。
客户端选择不同的工厂实现,就相当于是在切换不同的产品簇。
抽象工厂模式的缺点
不太容易扩展新的产品
如果需要给这个产品簇添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。
容易造成类层次复杂
在使用抽象工厂模式的时候,如果需要选择的层次过多,那么会造成这个类层次变得复杂。
举个例子来说,比如前面讲到的DAO的示例,现在这个DAO只有一个选择的层次,也就是选择使用关系型数据库来实现,还是使用XML来实现。现在考虑这样一种情况,如果关系型数据库实现里面又分成几种,比如,基于Oracle的实现,基于MySql的实现,基于SqlServer的实现等。
那么客户端怎么选择呢?不会把所有可能的情况全部都做到一个层次上吧,这个时候客户端就需要一层一层地选择,也就是整个抽象工厂的实现也需要分出层次来,每一层负责一种选择,也就是一层屏蔽一种变化,这样很容易造成负责的类层次结构。
抽象工厂模式的本质:选择产品簇的实现。
抽象工厂模式着重的就是为一个产品簇选择实现,定义在抽象工厂里面的方法通常是有联系的,它们都是产品的某一部分或者相互依赖的。如果抽象工厂里面只定义一个方法,直接创建产品,那么就退化成工厂方法了。
何时选用抽象工厂模式
建议在以下情况中选用抽象工厂模式。