“设计模式”学习之一:工厂方法与抽象工厂

来源:互联网 发布:仿淘宝商城源码html 编辑:程序博客网 时间:2024/05/20 18:17

一、工厂方法(Factory method,别名“虚构造器” VitualConstructor)

1、引言

典型过程:试想当你手头拥有服装厂(抽象类A),要生产一种服装(抽象类B),而你现在还不确定先生产服装中的哪种(比如上衣类ConcreteB1、裤子类ConcreteB2)。此时,可以用工厂方法,依据股东们开会研究后的决定(相当于客户代码如main函数临时调用),使用不同的厂房进行具体服装的生产。作为股东,只需要在办公室拍板说:“上衣!”,那么服装厂就会启动上衣厂房开始生产。换句话说,股东不用与产房打交道,只需要让服装厂临时启动厂房。

 

2、一般思路

它是唯一一种用于类的创建型模式。由创建者Factory(抽象基类)提供创建接口,由其子类ConcreteFactory(具体创建类)决定实例化哪一个具体产品类ConcreteProduct。下图中引入内部成员变量Num,作为判定标准。

 


 

3、典型代码

(1)在上图 ConcreteFactory 类声明中:Product*CreateProduct();

(2)在CreateProduct(intNum)函数体中:if(Num == 1) return new ConcreteProduct1();

(3)客户调用代码main()中:

Factory* fac = new ConcreteFactory();

Product* p = fac->CreateProduct(1);  // 1 or 2

可见:客户代码不再涉及与特定应用相关的类ConcreteProduct,只需调用接口。

 

4、应用提示

(1)一般而言,抽象基类Factory与Product存在一定的拥有关系(也就是书中提到的“聚合”)。例如,Application负责管理Document类。当然,也可连接两个平行的类层次,比如,图像类Figure和实现交互并保存所需操纵状态的类Manipulator;《Head first》中的Pizza和PizzaStore类。

(2)上图中的Factory基类也可以选择为具体类,这样为工厂方法(CreateProduct)提供一个缺省的实现,并且可以利用其子类改变父类创建的缺省ConcreteProduct类。

(3)为了使客户不用创建Factory的子类(即不用new ConcreteFactory()),可以使用模板,通过提供Factory的一个模板子类StandardCreator(以Product类作为模板参数)。这样客户只需要如下形式调用即可:StandardCreator<ConcreteProduct1> anyFactory;//不需要明确与ConcreteProduct1对应的**Factory子类名。

(4)一般称:Factory类提供了一个CreateProduct()工厂方法。而一般命名约定 用Class替代Product,如Class* DoMakeClass()。

(5)《Head first》引出了一个OO设计原则——“依赖倒置原则”:无论是高层组件还是低层,都要依赖抽象类,不要依赖具体类。PizzaStore和具体**Pizza都依赖于Pizza抽象类。引申过来,Factory类和ConcreteProduct1/2都依赖于Product类? 这个目前理解不透彻,还需要更进一步的体会。

(6)《Head first》提到的“简单工厂”没有完全符合“工厂方法”定义中的“定义一个接口”(即没有抽象层Factory,而是直接具体化)。故被称为一种编程习惯。

 

二、抽象工厂(Abstract Factory,别名“kit”)

1、引言

典型过程:在原服装厂的基础上,分立两个机构,分别负责童装和成人装的生产。同时在各个厂房分立两条工艺生产线。那么,股东同样只需要拍板说“产童装!”,不需要深入厂房,童装生产机构便会自动执行,生产出适合儿童的上衣和裤子。这就是典型的抽象工厂模式。

 

2、思路

下图中,提供了两个具体工厂,用于创建两个不同风格的产品系列1与2,各个产品系列当中都有A类和B类两种产品。当然,系列1中的A类产品有两种以上的选择,这是为了与上节中的工厂方法进行融合对比。作为客户,只需要与三个抽象接口打交道,不需要涉及产品的具体名称A1/2、B1/2。同时,这样可以保证同一个系列中产品风格的一致性和组件完整性。

 

3、典型代码

(1)在上图 ConcreteFactory1/2 类声明中:

AbstractProductA*CreateProductA(int Num);

AbstractProductB*CreateProductB();

(2)在ConcreteFactory1:: CreateProductB()函数体中:

 return new ConcreteProductB1();

其它类似。

(3)客户调用代码main()中:

AbstractFactory*cf1 = new ConcreteFactory1();

cf1->CreateProductA(1);

cf1->CreateProductB();

AbstractFactory*cf2 = new ConcreteFactory2();

cf2->CreateProductA(1);

cf2->CreateProductB();

可见:客户代码不再涉及与特定应用相关的类ConcreteProductA2/B1/B2等。

 

4、应用提示

(1)如图所示,通常会为每个产品系列定义一个具体工厂方法(Factory Method模式的create**())。如果有多个可能的系列,具体工厂ConcreteFactory*可以考虑使用Prototype模式(待学),它可以使得不是每个新的产品系列都需要一个新的具体工厂类。

(2)对于Abstract Factory模式,如果需要增加新产品如类C,对于Abstract Factory接口及其所有子类,则需要增加CreateProductC(),如此扩展性很差。可以通过对CreateProduct()增加一个参数来实现。这样,AbstractFactory类只需要一个“Create”操作和一个指示要创建种类的参数。上图中,有借鉴这个思想,但是只是针对低层具体类,可以提升到高层来完全实现。

(3)通常,一个应用中每个产品系列只需一个具体工厂实例,故工厂最好用Singleton模式只生成一个。

 

三、两者关系

(1)分类的区别:Factory method模式是类模式,用于处理父类和子类的关系;Abstract Factory模式是对象模式,处理对象间的关系。

(2)功能区别:Abstract Factory是为创建一组(有多个类)相关的产品提供创建接口,而Factory method是为一类相似产品提供创建接口或延迟对象的创建到子类中实现。

(3)通常,Abstract Factory模式是使用Factory method模式实现的(ConcreteFactory1/2)。

 

原创粉丝点击