3、工厂方法的隐藏
有时候,为了进一步简化客户端的使用,还可以对客户端隐藏工厂方法,此时,在工厂类中将直接调用产品类的业务方法,客户端无须调用工厂方法创建产品,直接通过工厂即可使用所创建的对象中的业务方法。
背景风格类并没有变化,实现代码如下:
#ifndef _BACKGROUND_STYLE_H_
#define _BACKGROUND_STYLE_H_
#include <iostream>
#include <string>
using namespace std;
//背景风格抽象类
class BackgroundStyle
{
public:
//虚方法,显示背景风格
virtual void DisplayStyle() = 0;
};
//古典风格背景类
class ClassicalStyle : public BackgroundStyle
{
public:
void DisplayStyle()
{
cout << "古典风格背景" << endl;
}
};
//潮流风格背景类
class FashionStyle : public BackgroundStyle
{
public:
void DisplayStyle()
{
cout << "潮流风格背景" << endl;
}
};
//艺术风格背景类
class ArtStyle : public BackgroundStyle
{
public:
void DisplayStyle()
{
cout << "艺术风格背景" << endl;
}
};
#endif
背景风格工厂类实现代码如下:
#ifndef _STYLE_FACTORY_H_
#define _STYLE_FACTORY_H_
#include "backgroundStyle.h"
//背景风格抽象工厂
class StyleFactory
{
private:
//保存创建的背景风格
BackgroundStyle * pBackgroundStyle;
public:
StyleFactory()
{
pBackgroundStyle = NULL;
}
~StyleFactory()
{
if( NULL != pBackgroundStyle )
{
delete pBackgroundStyle;
pBackgroundStyle = NULL;
}
}
//提供一个和风格类相同的方法,用于显示具体风格
void DisplayStyle()
{
pBackgroundStyle = CreateBackGroundStyle();
pBackgroundStyle->DisplayStyle();
}
//工厂方法,具体背景风格的创建过程由子类完成
virtual BackgroundStyle * CreateBackGroundStyle() = 0;
};
//古典风格工厂
class ClassicalStyleFactory : public StyleFactory
{
public:
BackgroundStyle * CreateBackGroundStyle()
{
BackgroundStyle * pClassicalStyle = new ClassicalStyle();
return pClassicalStyle;
}
};
//潮流风格工厂
class FashionStyleFactory : public StyleFactory
{
public:
BackgroundStyle * CreateBackGroundStyle()
{
BackgroundStyle * pFashionStyle = new FashionStyle();
return pFashionStyle;
}
};
//艺术风格工厂
class ArtStyleFactory : public StyleFactory
{
public:
BackgroundStyle * CreateBackGroundStyle()
{
BackgroundStyle * pArtStyle = new ArtStyle();
return pArtStyle;
}
};
#endif
StyleFactory背景风格抽象工厂中,提供了一个和背景风格类中一模一样的业务方法DisplayStyle(),该方法内部将调用工厂方法创建具体背景风格,并调用具体背景风格对象的DisplayStyle()方法。通常设计一个类的时候,需要考虑到单一原则,也就是这个类只实现一个业务功能。为了实现这个业务功能,把一些公用的业务方法放到抽象类中,子类就可以复用这个业务方法了。本例中,各子类工厂就能复用抽象工厂StyleFactory中的DisplayStyle()方法。同时在父类中定义一些虚业务方法,这些业务方法由子类具体实现。本例中,抽象工厂StyleFactory中的CreateBackGroundStyle是一个虚业务方法,为了实现创建背景风格的业务功能,由子类实现该业务方法,创建具体的背景风格。
测试实现代码如下:
#include <iostream>
#include "StyleFactory.h"
using namespace std;
int main()
{
/*********************创建古典风格背景***************************/
StyleFactory * pClassicalStyleFactory = new ClassicalStyleFactory();
pClassicalStyleFactory->DisplayStyle();
delete pClassicalStyleFactory;
pClassicalStyleFactory = NULL;
/*********************创建潮流风格工厂*************************/
StyleFactory * pFashionStyleFactory = new FashionStyleFactory();
pFashionStyleFactory->DisplayStyle();
delete pFashionStyleFactory;
pFashionStyleFactory = NULL;
/*********************创建艺术风格工厂*************************/
StyleFactory * pArtStyleFactory = new ArtStyleFactory();
pArtStyleFactory->DisplayStyle();
delete pArtStyleFactory;
pArtStyleFactory = NULL;
return 0;
}
编译并执行,结果如下:
通过将业务方法的调用移入工厂类,可以直接使用工厂对象来调用产品对象的业务方法,客户端无须直接使用工厂方法,工厂方法被隐藏了。在某些情况下我们也可以使用这种设计方案。
4、工厂方法模式总结
工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是对象创建型模式。
1. 主要优点
工厂方法模式的主要优点如下:
(1) 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。也就是说工厂方法模式封装了变化,封装了对象创建的具体细节,符合"封装变化原则"。
(2) 每一个具体工厂只负责创建一个对应的产品,符合"单一原则"。
(3) 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
(4)客户端只需要认识抽象的产品类,无需认识具体产品类,降低了客户端和具体产品类的耦合度。也就是说客户端针对接口进行编程,符合"针对接口进行编程而不是针对具体进行编程原则"。
2. 主要缺点
工厂方法模式的主要缺点如下:
(1) 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
3. 工厂方法模式具体应用
(1)通常在使用word办公软件的时候,会根据需要绘制出饼状图,柱状图,折线图等图形。可以提供一个抽象工厂类和三个工厂子类,创建具体图形。
(2)QQ空间背景样式,博客背景样式等都提供了各种风格的样式。可以提供一个抽象工厂类和三个工厂子类创建出各个不同的背景风格,用来装饰QQ空间。
(3)网页下载工具的开发: 根据需要可以下载新浪网页、腾讯网页、搜狐网页等。创建不同的网页工厂对象,下载对应类型的网页内容。
(4)淘宝购物最后一个支付环节,可以选择货到付款、网上银行、支付宝等类型支付。用户可以选择具体的支付方式完成订单,这也是工厂方法模式的一种应用。
(5)电影院打折算法: VIP5折、学生票5折、成人票正常收费等打折算法。
(6)多功能计算器的开发:封装加减乘除等运算操作(大话设计模式的例子)
(7)在很多游戏场合,游戏角色可以选择各种各样的武器,如:手枪、AK47、步枪、大刀等。
(8)如果电脑上装有QQ输入法、搜狗输入法、微软拼音输入法,用户可以设置使用哪种类型的输入法。类似的还可以设置IE浏览器、谷歌浏览器、火狐浏览器。可以设置word2003或者金山的WPS。这些都可以理解为工厂方法模式的一种运用。
(9)软件公司决策是否开发哪一种产品,银行卡识别、身份证识别还是驾驶证识别。
(10)开发火车票图像识别软件(OCR),对识别的结果可以保存为txt、word、pdf等格式。
(11)开发一套多种类型图片预览软件,可以读取jpg,bmp,gif等格式图片。
(11)生活中也有很多类似的工厂: 富士康代工工厂;安踏加工厂;咖啡生产基地;沃尔玛等超市提供各种产品供用户使用;肯德基马当劳等。