定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类
示例一:女娲造人扩展
造出来黑、白、黄种人,分别有性别分类
类图说明:一个接口,多个抽象类,N个实现类,每个人种都是一个抽象类,性别是在各个实现类中实现的。
1. 结构说明:
HumanFactory 接口,这个接口中定义了三个方法,分别用来产生三个不同肤色的人种
FemalFactory 和 MaleFactory 两个实现类,实现肤色、性别定义
AbstractBlackHuman 每个抽象类都有两个实现类,分别实现公共的、最具体的事物:肤色和语言。
2. 女娲造人类图9-2:
3. 女娲造人,代码清单9-2:
#include <QCoreApplication>
#include <QDebug>
////// ********** 1. 女娲造人扩展,代码清单9-1:***************//
class Human
{
public:
virtual void getColor() = 0;
virtual void talk() = 0;
virtual void getSex() = 0;
};
class YellowHuman:public Human
{
public:
virtual void getColor() {qDebug() << "YellowHuman color: yellow";}
virtual void talk() {qDebug() << "YellowHuman talk: ccc";}
};
class FYellowHuman:public YellowHuman
{
public:
virtual void getSex() {qDebug() << "*FemalYellowHuman*";}
};
class HumanFactory
{
public:
virtual Human* createYellowHuman() = 0;
};
class FemalFactory:public HumanFactory
{
public:
virtual Human* createYellowHuman()
{
FYellowHuman *hu = new FYellowHuman();
Human *human = dynamic_cast<Human*>(hu);
return human;
}
};
int main()
{
FemalFactory factory;
Human *human = factory.createYellowHuman();
human->getSex();
human->getColor();
human->talk();
return 0;
}
4. 这里只写出了制造女性黄种人的示例代码,其他类同
示例二:通用抽象工厂模式
1. 抽象工厂模式通用类图,类图9-3
说明:抽象工厂模式是工厂模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
2. 抽象工厂模式通用源码类图,类图9-4
说明:有两个相互影响的产品线(也叫做产品族),例如制造汽车的左侧门和右侧门,这两个应该是数量相等的——两个对象之间的约束,每个型号的车门都是不一样的,这是产品等级结构约束的。
3. 通用抽象工厂模式,代码清单9-2:
#include <QCoreApplication>
#include <QDebug>
////// ********** 2.抽象工厂模式的通用源码 ,代码清单9-1:***************//
//ProductA
class AbstractProductA
{
public:
void shareMethod(){}
virtual void doSomething() = 0;
};
class ProductA1:public AbstractProductA
{
public:
virtual void doSomething(){qDebug() << "ProductA1 method";}
};
class ProductA2:public AbstractProductA
{
public:
virtual void doSomething(){qDebug() << "ProductA2 method";}
};
//ProductB
class AbstractProductB
{
public:
void shareMethod(){}
virtual void doSomething() = 0;
};
class ProductB1:public AbstractProductB
{
public:
virtual void doSomething(){qDebug() << "ProductB1 method";}
};
class ProductB2:public AbstractProductB
{
public:
virtual void doSomething(){qDebug() << "ProductB2 method";}
};
//Creator
class AbstractCreator
{
public:
virtual AbstractProductA* createProductA() = 0;
virtual AbstractProductB* createProductB() = 0;
};
class Creator1:public AbstractCreator
{
public:
virtual AbstractProductA* createProductA()
{
ProductA1 *a1 = new ProductA1();
AbstractProductA *product = dynamic_cast<AbstractProductA*>(a1);
return product;
}
virtual AbstractProductB* createProductB()
{
ProductB1 *b1 = new ProductB1();
AbstractProductB *product = dynamic_cast<AbstractProductB*>(b1);
return product;
}
};
class Creator2:public AbstractCreator
{
public:
virtual AbstractProductA* createProductA()
{
ProductA2 *a2 = new ProductA2();
AbstractProductA *product = dynamic_cast<AbstractProductA*>(a2);
return product;
}
virtual AbstractProductB* createProductB()
{
ProductB2 *b2 = new ProductB2();
AbstractProductB *product = dynamic_cast<AbstractProductB*>(b2);
return product;
}
};
int main ()
{
Creator1 creator1;
Creator2 creator2;
AbstractProductA *a1 = creator1.createProductA();
AbstractProductA *a2 = creator2.createProductA();
AbstractProductB *b1 = creator1.createProductB();
AbstractProductB *b2 = creator2.createProductB();
a1->doSomething();
a2->doSomething();
b1->doSomething();
b2->doSomething();
return 0;
}
说明:场景类中,没有任何一个方法与实现类有关,对于一个产品来说,我们只要知道他的工厂方法就可以直接产生一个产品队形,无需关心他的实现类。
三、工厂方法模式的应用
优点:
- 封装性。每个产品的实现类不是高层模块要关心的,它要关心的是接口。只要知道工厂类,就可以创建出一个需要的对象。
- 产品族内的约束为非公开状态。具体的产品族内的约束是在工厂内实现的
缺点:
产品族扩展非常困难。以通用代码为例,如果要增加一个产品C,抽象类 AbstractCreator 要增加一个方法 createProductC() ,另外两个实现类都需要修改,违反了开闭原则。
使用场景:
一个对象族(或是一组没有任何关系的对象)都有相同的约束,则可以使用抽象工厂模式。
例如:一个文本编辑器和一个图片处理器,都是软件实体,但是在*nix 下的文本编辑器和 windows 下的文本编辑器虽然功能和界面都相同,但是代码实现不同,图片处理器也有类似情况。也就具有了共同的约束条件:操作系统类型。于是我们可以使用抽象工厂模式,产生不同操作系统下的编辑器和图片处理器。
注意事项:
在抽象工厂模式的缺点中,我们提到抽象工厂模式的产品族扩展比较困难,但是产品等级容易扩展。只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向扩展容易,纵向扩展困难。以女娲造人为例,产品登记汇总只有男、女两个性别,需要再增加双性人,呐我们需要增加咱哥产品类,分别对应不同的肤色,然后再创建一个工厂类,专门负责不同肤色人的双性人的创建任务,完全通过扩展来实现需求的变更,从这一点上看,抽象工厂模式符合开闭原则。
四、最佳实践
在软件产品开发过程中,涉及不同操作系统的时候,都可以考虑使用抽象工厂模式。例如一个应用,需要再三个不同平台(windows 、linux 、android)上运行,可以通过抽象工厂模式屏蔽掉操作系统对应用的影响。三个不同操作系统上的软件功能、应用逻辑、UI都应该是非常类似的,唯一不同的是调用不同的工厂方法,由不同的产品类去处理与操作系统交互的信息。
参考文献《秦小波. 设计模式之禅》(第2版) (华章原创精品) (Kindle 位置 308-310). 机械工业出版社