上回讲了Simple Factory和Factory Method。简单回顾一下:
-
Simple Factory:定义一个类(工厂)负责创建其他类(产品)的实例,产品实例通常具有共同的父类。
-
Factory Method:将工厂抽象一把,在父类中提供一个标准接口,由各个子类(具体工厂)决定创建什么样的实例(具体产品)。
Factory Method只能生产“一维”层次的,横向产品。也就是说,工厂生产的东东都是一类产品,都是由同一个父类派生的子类的对象。比如上次举例说到的,不管是Nokia的还是Motorola的,生产的都是手机,产品都是从Mobile派生出来的。
如果要想纵向的生产产品,比如,生产一个基站(这个东西好像大了点,但是偶实在想不出更好的产品了),Factory Method恐怕就不够用了。
各位看官请注意了,下面隆重介绍Abstract Factory!
1, 功能:
《设计模式》中的定义是“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”。所谓一系列,就说明他们不都是一个父类派生出来的,但是这些对象是为了以后的应用,或者整体应用所提供的。他们之间多少有些相关或者相互依赖。
2, 基本思想:
Factory Method可以理解为同一种产品的不同具体产品的工厂的抽象。每个具体的工厂生产出来的东东都是同一种产品(同一个父类)。
Abstract Factory是对不用种产品(但存在一定联系)的具体产品的工厂的抽象。每个具体工厂生产出来的东东不是同一种产品(不同的父类),但有一定联系(比如同一个厂家的产品,或者同一个窗口的组件)。
3, 适用情况:
一个系统要独立于它的产品的创建、组合和表示时;
一个系统要有多个产品系列中的一个来配置时;
需要强调一系列相关的产品对象的设计以便进行联合使用时;
当要提供一个产品类库,而只想显示它们的接口而不是实现时。
4, 案例举例:
实现在不同窗口系统之间的可移动性,比如Windows 操作系统中抽象工厂创建Windows下的窗口组件,Linux创建Linux的窗口组件,等等。
5, 结构:
6,代码示例:还是用Nokia和Moto两大通信公司的case来说明一下:
A. Nokia和Moto两个公司都生产手机
class
MobilePhone
{
public :
virtual void call() {cout << "Calling" << endl; } // 打电话
virtual void shortMsg() {cout << "Short Message" << endl;}; //收发短信
};
class NokiaPhone : public MobilePhone
{
virtual void call() { cout<<"Nokia calling"<< endl; }
virtual void shortMsg() { cout << "Nokia short message" << endl; }
};
class MotoPhone : public MobilePhone
{
virtual void call() { cout << "Moto calling"<< endl; }
virtual void shortMsg() { cout << "Moto short message" << endl; }
};
{
public :
virtual void call() {cout << "Calling" << endl; } // 打电话
virtual void shortMsg() {cout << "Short Message" << endl;}; //收发短信
};
class NokiaPhone : public MobilePhone
{
virtual void call() { cout<<"Nokia calling"<< endl; }
virtual void shortMsg() { cout << "Nokia short message" << endl; }
};
class MotoPhone : public MobilePhone
{
virtual void call() { cout << "Moto calling"<< endl; }
virtual void shortMsg() { cout << "Moto short message" << endl; }
};
B.Nokia和Moto两个公司都生产基站系统
class
BaseStation
{
public :
virtual void BTSControl() {cout << "Controlling BTS" << endl;}
virtual void BSCControl() {cout << "Controlling BSC" << endl;}
};
class NokiaBaseStation : public BaseStation
{
public :
void BTSControl() {cout << "Nokia BTS control" << endl;}
void BSCControl() {cout << "Nokia BSC control" << endl;}
};
class MotoBaseStation : public BaseStation
{
public :
void BTSControl() {cout << "Moto BTS control" << endl;}
void BSCControl() {cout << "Moto BSC control" << endl;}
};
{
public :
virtual void BTSControl() {cout << "Controlling BTS" << endl;}
virtual void BSCControl() {cout << "Controlling BSC" << endl;}
};
class NokiaBaseStation : public BaseStation
{
public :
void BTSControl() {cout << "Nokia BTS control" << endl;}
void BSCControl() {cout << "Nokia BSC control" << endl;}
};
class MotoBaseStation : public BaseStation
{
public :
void BTSControl() {cout << "Moto BTS control" << endl;}
void BSCControl() {cout << "Moto BSC control" << endl;}
};
C.抽象的工厂提供了标准的、生产所有不同种类产品(手机、基站)的接口。不同系列的产品由该系列的工厂生产。Nokia的手机和基站系统由Nokia的工厂生产,Motorola的手机和基站系统由Motorola公司生产。
class
Factory
{
public :
virtual MobilePhone * CreatePhone() = NULL;
virtual void DestroyPhone(MobilePhone * p) {if (p) delete p;};
virtual BaseStation * CreateBaseStation() = NULL;
virtual void DestroyBaseStation(BaseStation * b) {if (b) delete b;};
};
class NokiaFactory : public Factory
{
public :
MobilePhone * CreatePhone() { return (new NokiaPhone());}
BaseStation * CreateBaseStation() {return (new NokiaBaseStation());}
};
class MotoFactory : public Factory
{
MobilePhone * CreatePhone() { return (new MotoPhone());}
BaseStation * CreateBaseStation() {return (new MotoBaseStation());}
};
{
public :
virtual MobilePhone * CreatePhone() = NULL;
virtual void DestroyPhone(MobilePhone * p) {if (p) delete p;};
virtual BaseStation * CreateBaseStation() = NULL;
virtual void DestroyBaseStation(BaseStation * b) {if (b) delete b;};
};
class NokiaFactory : public Factory
{
public :
MobilePhone * CreatePhone() { return (new NokiaPhone());}
BaseStation * CreateBaseStation() {return (new NokiaBaseStation());}
};
class MotoFactory : public Factory
{
MobilePhone * CreatePhone() { return (new MotoPhone());}
BaseStation * CreateBaseStation() {return (new MotoBaseStation());}
};
D.下面客户端利用Factory创建不同系列的工厂对象,再利用这些工厂对象来创建对应系列的产品。
int
main()
{
Factory *nokiaFac = new NokiaFactory();
Factory *motoFac = new MotoFactory();
MobilePhone * nokia = nokiaFac-> CreatePhone();
MobilePhone * moto = motoFac-> CreatePhone();
nokia-> call();
nokia-> shortMsg();
moto-> call();
moto-> shortMsg();
BaseStation * nokiaBS = nokiaFac-> CreateBaseStation();
BaseStation * motoBS = motoFac-> CreateBaseStation();
nokiaBS-> BSCControl();
nokiaBS-> BTSControl();
motoBS-> BSCControl();
motoBS-> BTSControl();
nokiaFac-> DestroyBaseStation(nokiaBS);
nokiaFac-> DestroyPhone(nokia);
motoFac-> DestroyBaseStation(motoBS);
motoFac-> DestroyPhone(moto);
return 0 ;
}
{
Factory *nokiaFac = new NokiaFactory();
Factory *motoFac = new MotoFactory();
MobilePhone * nokia = nokiaFac-> CreatePhone();
MobilePhone * moto = motoFac-> CreatePhone();
nokia-> call();
nokia-> shortMsg();
moto-> call();
moto-> shortMsg();
BaseStation * nokiaBS = nokiaFac-> CreateBaseStation();
BaseStation * motoBS = motoFac-> CreateBaseStation();
nokiaBS-> BSCControl();
nokiaBS-> BTSControl();
motoBS-> BSCControl();
motoBS-> BTSControl();
nokiaFac-> DestroyBaseStation(nokiaBS);
nokiaFac-> DestroyPhone(nokia);
motoFac-> DestroyBaseStation(motoBS);
motoFac-> DestroyPhone(moto);
return 0 ;
}
上面的例子,用图来表示如下图:
7,总结
(1) 抽象工厂分离了客户和类的实现,客户通过工厂的抽象接口来得到产品的实例,客户不知道产品是如何生成的,具体产品类的名称也不会出现在客户代码中。
(2) Abstract Factory中,一个具体的工厂类在一个应用中仅出现一次(在初始化的时候),只需改变具体的工厂即可生产出一系列具有相关性的产品。
(3) Abstract Factory和Factory Method最大的区别就是:Factory Method针对同一级的产品,这些产品往往拥有共同的父类;Abstract Factory对应的是多个产品级的结构。所以在涉及到Abstract Factory的时候常常提到“产品族”的概念。产品族是指位于不同产品等级结构中,并且功能相互关联的产品系列,比如基站系统和手机属于不同级别的产品,但是他们是联合工作的。
(4) Abstract Factory也有不足之处。尤其是扩展新的产品系列,Abstract Factory的影响会非常大。比如我们要想新添加Alcatel产品系列,Alcatel又要生产
MSC
(移动交换中心)这个产品,此时不仅仅Abstract Factory需要修改以支持新产品,每个具体工厂类也必须修改(需要添加
MSC
产品的生产接口,尽管可能Nokia或者Moto不生产
MSC
)。这时,如果在Abstract Factory中的为生产
MSC
的接口提供缺省实现,可以避免修改已有具体工厂类(前题:这些具体工厂不负责生产新的产品)。
(5) 通常,Abstract Factory在整个应用中只有一个实例,所以可以结合Singleton模式。