设计模式【一】:抽象工厂
伪代码
class abstractFactory{
createSet(){}
createProductA(){};
createProductB(){};
};
productSet* makeProducts(abstractFactory& factory){
set = factory->createSet();
set.a = factory->createProductA();
set.b = factory->createProductB();
return set;
}
class factoryForSituation1:public abstractFactory{
createSet(){return set1}
createProductA(){return a1};
createProductB(){return b1};
};
productSet1 = makeProducts(factoryForSituation1);
class factoryForSituation2:public abstractFactory{
createSet(){return set1}
createProductA(){return a1};
createProductB(){return b2};
};
productSet2 = makeProducts(factoryForSituation2);
优缺点
优点
- 隔离实体类
工厂类继承了产品类的创建过程。对于调用者来说产品类的定义是不可见的。比如我只知道我要创建一个productSet的实例,但这个类的定义我无法修改。 - 易于修改整族的产品类
在一个情景下,抽象工厂一般只实例化一次,得到的工厂类生产适用于该情景的一整族产品。如果情景改变,重新实例化即可。这样整族的产品类被整体替换。调用者就不必对需要的产品类一一检查是否需要重新实现了——基于新的工厂类生产即可。 - 加强整族产品的联系
与上一点相似。使用抽象工厂可以确保得到的整族产品类适配于当前的情景。
缺点
- 修改单个产品类较困难
与优点伴生的就是修改单个产品类。由于工厂类是绑定一族的,因此想修改单个产品就需要对整个工厂类重新继承并实例化。A, B, C三个产品,我只要修改B,但我需要把A, B, C全部重新写一遍。
何时使用
- 一个系统需要与其产品的生产、构成、表现方式独立。
- 系统应配置有多个产品族之一。比如有三个族:(A, B, C)、(A, C, D)、(B, C, D),需要根据情境选择一个族。
- 一族的多个产品需要一起使用,程序员为确保这种关系可以把这些产品放在同一个工厂类里。
- 或者程序员只是对一个产品库提供一个统一接口。
实现时技巧
- 实例化的工厂类最好是单例。一个情境下只实例化一次。
- 生产产品时
- 由于抽象工厂只提供接口,需要一个配套的生产方法,比如伪代码中的
makeProducts()
。 - 批量生产产品时可采取原型模式
- 设计可扩展的工厂。比如给生产方法添加一个与情境关联的参数,这样在更改情境时就不必重新实例化一个工厂,只需在调用生产方法时更改参数;但这样会降低设计的安全性。