6 抽象工厂模式
问题引入:
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在
大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产。
案例:
模拟一个组装台式电脑的小案例,客户端、装机工程师、电脑配件(主板、CPU)
未使用抽象工厂模式代码实现:
1、CPU以及主板规则定义
// 设计一个CPU规则(接口)
public interface CPU {
//CPU负责核心计算
void centerCalculate();
}
// 设计一个主板的规则(接口)
public interface MainBoard {
//主板,可以安装组件(CPU+显卡+内存)
void installCPU();
}
2、主板的具体实现类
//这是一个具体的微星品牌主板
public class MSIMainBoard implements MainBoard{
//属性--名字
private String name;
//属性--主板上CPU针孔数
private int CPUPinHoles;
//带参数的构造方法
public MSIMainBoard(String name, int CPUPinHoles) {
this.name = name;
this.CPUPinHoles = CPUPinHoles;
}
public void installCPU() {
System.out.println("这是"+this.name+"主板,CPU的针孔数为"+this.CPUPinHoles);
}
}
//这是一个具体的华硕品牌主板
public class ASUSMainBoard implements MainBoard{
//属性--名字
private String name;
//属性--主板上CPU针孔数
private int CPUPinHoles;
//带参数的构造方法
public ASUSMainBoard(String name, int CPUPinHoles) {
this.name = name;
this.CPUPinHoles = CPUPinHoles;
}
public void installCPU() {
System.out.println("这是"+this.name+"主板,CPU的针孔数为"+this.CPUPinHoles);
}
}
3、CPU具体实现类
//这是一个AMD品牌的CPU
public class AMDCPU implements CPU {
//属性名字
private String name;
//属性针脚数
private int pins;
//带参数的构造方法
public AMDCPU(String name, int pins) {
this.name = name;
this.pins = pins;
}
public void centerCalculate() {
System.out.println("这是"+this.name+"CPU,配有"+this.pins+"针脚");
}
}
//这是英特尔品牌的CPU
public class InterCPU implements CPU {
//属性名字
private String name;
//属性针脚数
private int pins;
//带参数的构造方法
public InterCPU(String name, int pins) {
this.name = name;
this.pins = pins;
}
public void centerCalculate() {
System.out.println("这是"+this.name+"CPU,配有"+this.pins+"针脚");
}
}
4、CPU工厂和主板工厂
//这是一个用来制造主板的工厂
public class MainBoardFactory {
//静态工厂方法来实现
public static MainBoard createMainBoard(int type) {
MainBoard mainBoard = null;
if (type == 1) {//用华硕
mainBoard = new ASUSMainBoard("ASUS", 1155);
} else if (type == 2) {//用微星
mainBoard = new MSIMainBoard("MSI", 775);
} else if (type == 3) {
}
return mainBoard;
}
}
//这是一个用来制作CPU对象的工厂
public class CPUFactory {
//静态工厂方法
public static CPU createCPU(int type) {
CPU cpu = null;
if (type == 1) {//inter
cpu = new InterCPU("Inter", 1155);
} else if (type == 2) {
cpu = new AMDCPU("AMD", 775);
} else if (type == 3) {
}
return cpu;
}
}
5、装机工程师
/**
* 这是一个电脑工程师
* 他负责将电脑的硬件组装在一起
* 主板+CPU
*/
public class ComputerEngineer {
//修改一下组装电脑的方法
// 组装电脑的时候 用户是不知道具体硬件对象 只知道某一个类型
public void assembleComputer(int mainBoardType,int cpuType){
//根据用户提供的种类
//通过工厂创建两个硬件对象
MainBoard mainBoard = MainBoardFactory.createMainBoard(mainBoardType);
CPU cpu = CPUFactory.createCPU(cpuType);
mainBoard.installCPU();
cpu.centerCalculate();
}
}
6、客户端
public class TestMain {
public static void main(String[] args) {
//1.工程师
ComputerEngineer engineer = new ComputerEngineer();
//2.工程师做事
engineer.assembleComputer(1,1);
}
}
测试结果:
这是ASUS主板,CPU的针孔数为1155
这是InterCPU,配有1155针脚
问题分析:
以前的简单工厂模式或者是工厂方法模式,更注重的是单个对象的创建,每一个工厂 只负责创建当前工厂的对象,这个对象与其他工厂或者是其他对象产生的结
果不一定匹配,就好像CPU工厂 关注CPU对象的创建,主板工厂 关注主板对象的创建,两个对象之间的关联关系呢? 工厂并不关注,但是两个产品是一个系列的
才可以搭配在一起。所以上述存在搭配错误的问题,当用户选择1类型的主板搭配2类型的CPU是不可能能装上的。
抽象工厂简单概述:
抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
使用抽象工厂模式代码实现:
1、CPU以及主板规则定义
// 设计一个CPU规则(接口)
public interface CPU {
//CPU负责核心计算
void centerCalculate();
}
// 设计一个主板的规则(接口)
public interface MainBoard {
//主板,可以安装组件(CPU+显卡+内存)
void installCPU();
}
2、主板的具体实现类
//这是一个具体的微星品牌主板
public class MSIMainBoard implements MainBoard{
//属性--名字
private String name;
//属性--主板上CPU针孔数
private int CPUPinHoles;
//带参数的构造方法
public MSIMainBoard(String name, int CPUPinHoles) {
this.name = name;
this.CPUPinHoles = CPUPinHoles;
}
public void installCPU() {
System.out.println("这是"+this.name+"主板,CPU的针孔数为"+this.CPUPinHoles);
}
}
//这是一个具体的华硕品牌主板
public class ASUSMainBoard implements MainBoard{
//属性--名字
private String name;
//属性--主板上CPU针孔数
private int CPUPinHoles;
//带参数的构造方法
public ASUSMainBoard(String name, int CPUPinHoles) {
this.name = name;
this.CPUPinHoles = CPUPinHoles;
}
public void installCPU() {
System.out.println("这是"+this.name+"主板,CPU的针孔数为"+this.CPUPinHoles);
}
}
3、CPU具体实现类
//这是一个AMD品牌的CPU
public class AMDCPU implements CPU {
//属性名字
private String name;
//属性针脚数
private int pins;
//带参数的构造方法
public AMDCPU(String name, int pins) {
this.name = name;
this.pins = pins;
}
public void centerCalculate() {
System.out.println("这是"+this.name+"CPU,配有"+this.pins+"针脚");
}
}
//这是英特尔品牌的CPU
public class InterCPU implements CPU {
//属性名字
private String name;
//属性针脚数
private int pins;
//带参数的构造方法
public InterCPU(String name, int pins) {
this.name = name;
this.pins = pins;
}
public void centerCalculate() {
System.out.println("这是"+this.name+"CPU,配有"+this.pins+"针脚");
}
}
3、抽象工厂规则定义
/**
* 一个抽象工厂的规则(接口)
* 这个工厂中定义 两个产生具体硬件的方法
* 两个方法分别产生主板+CPU对象
* 两个方法的具体实现是配套的 互相关联
*/
public interface AbstractFactory {
MainBoard createMainBoard();
CPU createCPU();
}
4、方案的具体实现
/**
* 这是一种装机方案
* 华硕主板+英特尔CPU
*/
public class PlanA implements AbstractFactory {
@Override
public MainBoard createMainBoard() {
return new ASUSMainBoard("ASUS",1155);
}
@Override
public CPU createCPU() {
return new InterCPU("Inter",1155);
}
}
/**
* 这是一种装机方案
* 华硕主板+英特尔CPU
*/
public class PlanB implements AbstractFactory {
@Override
public MainBoard createMainBoard() {
return new ASUSMainBoard("MSI",775);
}
@Override
public CPU createCPU() {
return new InterCPU("AMD",775);
}
}
5、客户端测试
public class TestMain {
public static void main(String[] args) {
//1.需要一个工程师
ComputerEngineer engineer = new ComputerEngineer();
//2.用户提供一个装机方案
AbstractFactory plan = new PlanA();
//3.工程师做事
engineer.assembleComputer(plan);
}
}
测试结果:
这是ASUS主板,CPU的针孔数为1155
这是InterCPU,配有1155针脚
改进分析:
抽象工厂的功能是为了一系列相关对象或者互相依赖的对象创建 而设置的,抽象工厂中的方法不是随便创建的 而是一系列的相关方法,去理解刚才我们的抽象工
厂 两个方法刚好是为了组装一台电脑,从某种意义上来讲 抽象工厂创建出来的产品是一个系列 而不是某一个对象,这个工厂创建出来的产品是套装 产品簇,表
一种方案,或者是一个体系。
开闭原则的倾斜性:
在抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂模式的这种性质称为“开闭原则”的倾斜性。“开闭原则”要求系统对扩展
开放,对修改封闭,通过扩展达到增强其功能的目的,对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
(1) 增加产品族:对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
(2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
正因为抽象工厂模式存在“开闭原则”的倾斜性,它以一种倾斜的方式来满足“开闭原则”,为增加新产品族提供方便,但不能为增加新产品结构提供这样的方便,因
此要求设计人员在设计之初就能够全面考虑,不会在设计完成之后向系统中增加新的产品等级结构,也不会删除已有的产品等级结构,否则将会导致系统出现较大
的修改,为后续维护工作带来诸多麻烦。
抽象工厂模式总结:
抽象工厂模式是工厂方法模式的进一步延伸,由于它提供了功能更为强大的工厂类并且具备较好的可扩展性,在软件开发中得以广泛应用,尤其是在一些框架和
API类库的设计中,例如在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操
作系统一致的外观界面。抽象工厂模式也是在软件开发中最常用的设计模式之一。
主要优点:
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
- 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
主要缺点:
- 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。