抽象工厂模式
先说一个场景:大学的时候,为了打游戏打的爽,买现成的电脑不是CPU不满意就是内存堪忧,那怎么办呢?组装电脑呗,把自己想要CPU,主板,内存,硬盘等配件搞来组装
但这样有一系列的问题,比如选择CPU的时候,只有把品牌,型号,主频等确定下来,才能确定具体的CPU,同样的问题也发生在主板上
最后还有配件的兼容性,不能说买最好的CPU和主板搭配在一起,肯定好使.如果CPU针脚数和主板提供的CPU插口不兼容,是无法组装的.
那么这样就可以得出一个结论:装机方案是有整体性的,里面选择的各个配件之间是有联系的
下面组装过程只考虑CPU和主板
因此当装机师为不同的客户组装电脑时,只需要按照客户的装机方案(方案已确定),去获取相应的配件,然后组装就可以了
那么如何用程序来实现这个过程呢?
不用模式的解决方案
考虑客户的功能,需要选择自己需要的CPU和主板,然后告诉装机师自己的选择,接下来就是装机师组装机器了
对于装机师来说,只是知道CPU和主板的接口,而不知道具体实现,很明显可以使用简单工厂模式
下面来撸代码:
- CPU和主板的接口(父类):
class CPU
{
//运算
public void calculate()
}
class MainBoard
{
//安装CPU
public void installCPU()
}
- 具体的CPU实现
class IntelCPU : CPU
{
//针脚数
int pins = 0
intelCPU(int pins)
{
self.pins = pins
}
public void calculate()
{
print("现在使用的是intel CPU,pins="+pins)
}
}
class AMDCPU : CPU
{
//针脚数
int pins = 0
intelCPU(int pins)
{
self.pins = pins
}
public void calculate()
{
print("现在使用的是锐龙 CPU,pins="+pins)
}
}
- 具体的主板实现
public class IntelMainboard implements MainBoard {
//CPU插槽的孔数
private int cpuHoles = 0;
public GAMainboard(int cpuHoles){
this.cpuHoles = cpuHoles;
}
public void installCPU() {
print("now in IntelMainboard,cpuHoles=" + cpuHoles);
}
}
public class AMDMainboard implements MainBoard{
//CPU插槽的孔数
private int cpuHoles = 0;
public AMDMainboard(int cpuHoles){
this.cpuHoles = cpuHoles;
}
public void installCPU() {
print("now in AMDMainboard,cpuHoles=" + cpuHoles);
}
}
- 创建CPU和主板的工厂
public class CPUFactory {
createCPU(int type){
CPU cpu = null;
//根据参数来选择并创建相应的CPU对象
if(type==1){
cpu = new IntelCPU(100);
}else if(type==2){
cpu = new AMDCPU(200);
}
return cpu;
}
}
public class MainboardFactory {
createMainboard(int type){
MainboardApi mainboard = null;
//根据参数来选择并创建相应的主板对象
if(type==1){
mainboard = new IntelMainboard(100);
}else if(type==2){
mainboard = new AMDMainboard(200);
}
return mainboard;
}
}
- 装机
-(void)createComputer(int cpuType, int mainBoardType){
CPU *cpu = [CPUFactory createCPUWithType:cpuType];
MainBoard *mainBoard = [MainBoardFactory createMainBoardWithType:mainBoardType];
[cpu calculate];
[mainBoard installCPU];
}
- 客户端调用
ComputerEngineer *eng = [ComputerEngineer new];
eng.createComputer(1,1);
上面的代码完美实现了装机过程,只知CPU和主板的接口,不知道具体的实现,但大家会发现有个问题?CPU和主板是有联系的,需要匹配,但上面的实现并没有维护这种关系
如何解决问题呢?抽象工厂模式
抽象工厂模式来解决
定义: 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类
分析上面的问题,和抽象工厂模式的定义得出两个要点:
- 只知道所需要的一系列对象的接口,而不知道具体实现
- 一系列对象是相关或者相互依赖的
看到这肯定会有人在想只知接口不知具体实现不是简单工厂模式吗?这里强调一下抽象工厂模式和简单工厂模式的区别:简单工厂模式关注的是单个产品对象的创建,比如创建CPU的工厂方法,只关心如何创建CPU对象,而创建主板的工厂方法,就只关心如何创建主板对象.抽象工厂模式要创建的是一系列的产品对象,而且这一系列对象是构成新对象所需要的组成部分,也就是这一系列被创建的对象相互之间是有约束的
那么抽象工厂模式是怎么解决问题的呢?
在抽象模式里面,会定义一个抽象工厂,在里面虚拟的创建客户端需要的这一系列对象.这里的虚拟就是定义创建这些对象的抽象方法,并不去真的实现,然后由具体的抽象工厂的子类来提供这一系列对象的创建,这样一来可以为同一抽象工厂提供很多不同的实现,那么创建的这一系列对象也就不一样了,也就是说,抽象工厂在这里起到一个约束左右,并提供所有子类的一个统一外观,来让客户端使用
模式结构
AbstractFactory:抽象工厂,定义创建一系列产品对象的操作接口。
ConcreteFactory:具体的工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建。
AbstractProduct:定义一类产品对象的接口。
ConcreteProduct:具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对象。
Client:客户端,主要使用抽象工厂来获取一系列所需要的产品对象,然后面向这些产品对象的接口编程,以实现需要的功能。
重写示例
- 具体的CPU和主板类不变
- 抽象工厂
class AbFactory:
{
-(CPU *)createCPU;
-(MainBoard *)createMainBoard;
}
- 具体工厂类
class IntelFactory : AbFactory
- (CPU *)createCPU
{
return [IntelCPU createCPUWithPins:100];
}
- (MainBoard *)createMainBoard
{
return [IntelMainBoard createMainBoardWithCpuHoles:100];
}
class AMDFactory : AbFactory
- (CPU *)createCPU
{
return [AMDCPU createCPUWithPins:200];
}
- (MainBoard *)createMainBoard
{
return [AMDMainBoard createMainBoardWithCpuHoles:200];
}
- 装机师装机
class computerEngineer:
- (void)makeComputer:(AbFactory *)factory
{
CPU *cpu = [factory createCPU];
MainBoard *mainBoard = [factory createMainBoard];
[cpu calculate];
[mainBoard installCPU];
}
抽象工厂模式的优缺点
优点:
-
降低耦合性
抽象工厂模式将具体产品的创建延迟到具体工厂的子类中,这样就将对象的创建封装起来,可以减少客户端与具体产品类之间的依赖,从而降低系统耦合性
-
符合开-闭原则
新增一种产品类时,只需要添加相应的具体产品类和相应的工厂子类即可
缺点
很难支持新种类产品的变化,如果添加了新种类,此时就必须去修改抽象工厂的接口,这样就涉及到抽象工厂类以及所有子类的改变,违背了"开发-封闭"原则