设计模式08---设计模式之抽象工厂模式(Abstract Factory)
1.场景模拟
举个生活中常见的例子:组装电脑,我们在组装电脑的时候,通常要选择一系列的配件,比如选择CPU时候,需要注意品牌,型号,针脚数目,主频,只有这些都确定下来,才能确定一个CPU。同样,主板也是这样的。对于装机工程师而言,他只知道装一台电脑需要使用相应的配件,具体的配件,还是由客户说了算。
2.一般的解决方案(简单工厂)
2.1CPU接口
package demo06.abstractfactory.example1; /** * CPU的接口 */ public interface CPUApi { /** * 示意方法,CPU具有运算的功能 */ public void calculate(); }
2.2主板接口
package demo06.abstractfactory.example1; /** * 主板的接口 */ public interface MainboardApi { /** * 示意方法,主板都具有安装CPU的功能 */ public void installCPU(); }
2.3 Inter CPU实现
package demo06.abstractfactory.example1; /** * Intel的CPU实现 */ public class IntelCPU implements CPUApi { /** * CPU的针脚数目 */ private int pins = 0; /** * 构造方法,传入CPU的针脚数目 * * @param pins * CPU的针脚数目 */ public IntelCPU(int pins) { this.pins = pins; } public void calculate() { System.out.println("now in Intel CPU,pins=" + pins); } }
2.4 AMD的CPU实现
package demo06.abstractfactory.example1; /** * AMD的CPU实现 */ public class AMDCPU implements CPUApi { /** * CPU的针脚数目 */ private int pins = 0; /** * 构造方法,传入CPU的针脚数目 * * @param pins * CPU的针脚数目 */ public AMDCPU(int pins) { this.pins = pins; } public void calculate() { System.out.println("now in AMD CPU,pins=" + pins); } }
2.5技嘉的主板实现
package demo06.abstractfactory.example1; /** * 技嘉的主板 */ public class GAMainboard implements MainboardApi { /** * CPU插槽的孔数 */ private int cpuHoles = 0; /** * 构造方法,传入CPU插槽的孔数 * * @param cpuHoles * CPU插槽的孔数 */ public GAMainboard(int cpuHoles) { this.cpuHoles = cpuHoles; } public void installCPU() { System.out.println("now in GAMainboard,cpuHoles=" + cpuHoles); } }
2.6微星的主板
package demo06.abstractfactory.example1; /** * 微星的主板 */ public class MSIMainboard implements MainboardApi { /** * CPU插槽的孔数 */ private int cpuHoles = 0; /** * 构造方法,传入CPU插槽的孔数 * * @param cpuHoles * CPU插槽的孔数 */ public MSIMainboard(int cpuHoles) { this.cpuHoles = cpuHoles; } public void installCPU() { System.out.println("now in MSIMainboard,cpuHoles=" + cpuHoles); } }
2.7创建CPU工厂
package demo06.abstractfactory.example1; /** * 创建CPU的简单工厂 */ public class CPUFactory { /** * 创建CPU接口对象的方法 * @param type 选择CPU类型的参数 * @return CPU接口对象的方法 */ public static CPUApi createCPUApi(int type){ CPUApi cpu = null; //根据参数来选择并创建相应的CPU对象 if(type==1){ cpu = new IntelCPU(1156); }else if(type==2){ cpu = new AMDCPU(939); } return cpu; } }
2.8创建主板工厂
package demo06.abstractfactory.example1; /** * 创建主板的简单工厂 */ public class MainboardFactory { /** * 创建主板接口对象的方法 * * @param type * 选择主板类型的参数 * @return 主板接口对象的方法 */ public static MainboardApi createMainboardApi(int type) { MainboardApi mainboard = null; // 根据参数来选择并创建相应的主板对象 if (type == 1) { mainboard = new GAMainboard(1156); } else if (type == 2) { mainboard = new MSIMainboard(939); } return mainboard; } }
2.9工程师实现代码
package demo06.abstractfactory.example1; /** * 装机工程师的类 */ public class ComputerEngineer { /** * 定义组装机器需要的CPU */ private CPUApi cpu = null; /** * 定义组装机器需要的主板 */ private MainboardApi mainboard = null; /** * 装机过程 * * @param cpuType * 客户选择所需CPU的类型 * @param mainboardType * 客户选择所需主板的类型 */ public void makeComputer(int cpuType, int mainboardType) { // 1:首先准备好装机所需要的配件 prepareHardwares(cpuType, mainboardType); // 2:组装机器 // 3:测试机器 // 4:交付客户 } /** * 准备装机所需要的配件 * * @param cpuType * 客户选择所需CPU的类型 * @param mainboardType * 客户选择所需主板的类型 */ private void prepareHardwares(int cpuType, int mainboardType) { // 这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个 // 可是,装机工程师并不知道如何去创建,怎么办呢? // 直接找相应的工厂获取 this.cpu = CPUFactory.createCPUApi(cpuType); this.mainboard = MainboardFactory.createMainboardApi(mainboardType); // 测试一下配件是否好用 this.cpu.calculate(); this.mainboard.installCPU(); } }
2.90客户端测试
package demo06.abstractfactory.example1; public class Client { public static void main(String[] args) { // 创建装机工程师对象 ComputerEngineer engineer = new ComputerEngineer(); // 告诉装机工程师自己选择的配件,让装机工程师组装电脑 engineer.makeComputer(1, 2); } }
3.问题:
问题出现了:如果client传入的参数时1,2,那么装机不匹配就会失败,所以就会出现问题,如何解决呢?
4.解决方法(抽象工厂模式)
4.1模式定义:
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
4.2模式的结构和说明
5.示例代码(抽象工厂模式)
5.1抽象工厂接口
package demo06.abstractfactory.example2; /** * 抽象工厂的接口,声明创建抽象产品对象的操作 */ public interface AbstractFactory { /** * 示例方法,创建抽象产品A的对象 * * @return 抽象产品A的对象 */ public AbstractProductA createProductA(); /** * 示例方法,创建抽象产品B的对象 * * @return 抽象产品B的对象 */ public AbstractProductB createProductB(); }
5.2产品A接口
package demo06.abstractfactory.example2; /** * 抽象产品A的接口 */ public interface AbstractProductA { // 定义抽象产品A相关的操作 }
5.3产品B接口
package demo06.abstractfactory.example2; /** * 抽象产品B的接口 */ public interface AbstractProductB { // 定义抽象产品B相关的操作 }
5.4产品A实现
package demo06.abstractfactory.example2; /** * 产品A的具体实现 */ public class ProductA1 implements AbstractProductA { // 实现产品A的接口中定义的操作 } package demo06.abstractfactory.example2; /** * 产品A的具体实现 */ public class ProductA2 implements AbstractProductA { // 实现产品A的接口中定义的操作 }
5.5产品B实现
package demo06.abstractfactory.example2; /** * 产品B的具体实现 */ public class ProductB1 implements AbstractProductB { // 实现产品B的接口中定义的操作 } package demo06.abstractfactory.example2; /** * 产品B的具体实现 */ public class ProductB2 implements AbstractProductB { // 实现产品B的接口中定义的操作 }
5.6具体工厂实现
package demo06.abstractfactory.example2; /** * 具体的工厂实现对象,实现创建具体的产品对象的操作 */ public class ConcreteFactory1 implements AbstractFactory { public AbstractProductA createProductA() { return new ProductA1(); } public AbstractProductB createProductB() { return new ProductB1(); } } package demo06.abstractfactory.example2; /** * 具体的工厂实现对象,实现创建具体的产品对象的操作 */ public class ConcreteFactory2 implements AbstractFactory { public AbstractProductA createProductA() { return new ProductA2(); } public AbstractProductB createProductB() { return new ProductB2(); } }
5.7客户端
package demo06.abstractfactory.example2; public class Client { public static void main(String[] args) { // 创建抽象工厂对象 AbstractFactory af = new ConcreteFactory1(); // 通过抽象工厂来获取一系列的对象,如产品A和产品B af.createProductA(); af.createProductB(); } }
6.重写示例代码
6.1结构图
6.2抽象工厂接口
package demo06.abstractfactory.example3; /** * 抽象工厂的接口,声明创建抽象产品对象的操作 */ public interface AbstractFactory { /** * 创建CPU的对象 * * @return CPU的对象 */ public CPUApi createCPUApi(); /** * 创建主板的对象 * * @return 主板的对象 */ public MainboardApi createMainboardApi(); }
6.3装机方案一
package demo06.abstractfactory.example3; /** * 装机方案一:Intel 的CPU + 技嘉的主板 这里创建CPU和主板对象的时候,是对应的,能匹配上的 */ public class Schema1 implements AbstractFactory { public CPUApi createCPUApi() { return new IntelCPU(1156); } public MainboardApi createMainboardApi() { return new GAMainboard(1156); } }
6.4装机方案二
package demo06.abstractfactory.example3; /** * 装机方案二:AMD的CPU + 微星的主板 这里创建CPU和主板对象的时候,是对应的,能匹配上的 */ public class Schema2 implements AbstractFactory { public CPUApi createCPUApi() { return new AMDCPU(939); } public MainboardApi createMainboardApi() { return new MSIMainboard(939); } }
6.5装机工程师
package demo06.abstractfactory.example3; /** * 装机工程师的类 */ public class ComputerEngineer { /** * 定义组装机器需要的CPU */ private CPUApi cpu = null; /** * 定义组装机器需要的主板 */ private MainboardApi mainboard = null; /** * 装机过程 * * @param schema * 客户选择的装机方案 */ public void makeComputer(AbstractFactory schema) { // 1:首先准备好装机所需要的配件 prepareHardwares(schema); // 2:组装机器 // 3:测试机器 // 4:交付客户 } /** * 准备装机所需要的配件 * * @param schema * 客户选择的装机方案 */ private void prepareHardwares(AbstractFactory schema) { // 这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个 // 可是,装机工程师并不知道如何去创建,怎么办呢? // 使用抽象工厂来获取相应的接口对象 this.cpu = schema.createCPUApi(); this.mainboard = schema.createMainboardApi(); // 测试一下配件是否好用 this.cpu.calculate(); this.mainboard.installCPU(); } }
6.6客户端使用
package demo06.abstractfactory.example3; public class Client { public static void main(String[] args) { // 创建装机工程师对象 ComputerEngineer engineer = new ComputerEngineer(); // 客户选择并创建需要使用的装机方案对象 AbstractFactory schema = new Schema1(); // 告诉装机工程师自己选择的装机方案,让装机工程师组装电脑 engineer.makeComputer(schema); } }
7.抽象工厂模式讲解
7.1抽象工厂和DAO
DAO是数据访问对象,是J2EE中的一种标准的模式,是为了解决访问数据不同而产生的一种设计模式。这种设计模式简言之是:分层设计的思想。
在实现DAO模式的时候,多用工厂的策略,最常用的就是抽象工厂模式,当然最好结合工厂方法模式。
7.2抽象工厂的优缺点
优点:分离接口和实现
使得切换产品簇更加容易。
缺点:不太容易扩展新的产品
容易造成类层次复杂
7.3抽象工厂模式的本质
选择产品簇的实现