工厂方法的说明文档——设计模式之抽象工厂
凌丽软件工作室 http://china.wosens.net
编写:梅文海
日期:2005.11.3
更新日期:2005.12.21
工厂方法说明:
顾名思义,工厂就是提供制造物品的一个容器,方法则是制造的具体手段,那么工厂方法就可以
看做是用来制造对象的手段。工厂方法提供了一个无须指定具体类而是依赖接口来产生一个新的对象。
下面用例子说明:
有如下类
1.人
2.头
3.胳膊
4.制造人
其中制造人的伪代码如下:
人* 制造人::创造人对象{
人* 人指针=new 人;
头* 头指针=new 头;
胳膊* 胳膊指针=new 胳膊;
人指针->AddHead(头指针);
人指针->AddArm(胳膊指针);
return 人指针;
}
我们从上面的代码可以看出,作为人的组成部分的“头”和“胳膊”,都实行了硬编码,假如
我们要生成一个魔法师(一个相似但不同的对象),他的头和胳膊都是具有魔法的,如下类:
1.魔法头
2.魔法胳膊
这样一来,制造魔法师的代码就要重写,如果我们先定义一个工厂类,如下:
class 人制造工厂{
public:
virtual 人* 制造人() const {return new 人;}
virtual 头* 制造头() const {return new 头;}
virtual 胳膊* 制造胳膊() const {return new 胳膊;}
}
再重新改写“制造人”的“创造人对象”方法,如下:
人* class 制造人::创造人对象(人制造工厂& 工厂){
人* 人指针=工厂.制造人();
头* 头指针=工厂.制造头();
胳膊* 胳膊指针=工厂.制造胳膊();
人指针->AddHead(头指针);
人指针->AddArm(胳膊指针);
return 人指针;
}
再编写魔法师的工厂方法,如下:
class 魔法师制造工厂:public 人制造工厂{
virtual 人* 制造人() const {return new 人;}
virtual 头* 制造头() const {return new 魔法头;}
virtual 胳膊* 制造胳膊() const {return new 魔法胳膊;}
}
如此一来,我们创建魔法师的代码就可以这样写了:
{
制造人 制造人实例;
魔法师制造工厂 魔法师工厂;
制造人实例.创造人对象(魔法师工厂);
}
使用了工厂方法后,创建对象的过程简单化了,同时也让软件有了很好的扩展能力,只要
继承原始的工厂类就可以实现创建任意的对象。
★ 示例
说明:下面是工厂方法的一个具体应用,它使用一个动态链接库的方法构造对象
意义:
1.解决了动态库不能调用类的问题
2.可以完全代替了普通只有函数的动态链接库,同时简化了获取函数指针的过程
原理:
1.动态链接库动态调用
2.类的继承
3.动态链接库加载到进程空间原理,保证了指针可以指向动态库构造的对象
4.函数指针原理
实现方法:
1.创建一个接口类(CPutBox),将接口类中的方法都设置成虚拟方法
2.在接口类中定义一个函数指针;例如:typedef CPutBox* (*PubBoxFactory)();
3.创建一个动态链接库,把接口类加入到项目中
4.从接口类派生一个新类(CPutBoxChild),把要实现的代码都写的这个新的类中
5.在新派生类的 .cpp 文件中定义实现一个创建类的方法;例如:
CPutBox *CreatePutBox() {
return new CPutBoxChild();
}
6.在 .Def 文件中导出创建类的函数,如:
EXPORTS
CreatePutBox @1
7.加入接口类到主工程
8.在要使用动态链接库的地方加入以下代码:
HMODULE hDll;
PubBoxFactory pPutBoxFactory;
CPutBox* pPutBox;
hDll=LoadLibrary("FactoryDll.dll"); // 装载动态链接库
// 获得动态链接库的工厂方法地址(指针)
pPutBoxFactory=(PubBoxFactory)GetProcAddress(hDll, "CreatePutBox");
if(hDll && pPutBoxFactory){
pPutBox=pPutBoxFactory(); // 调用工厂方法,构造动态链接库中类的对象
pPutBox->Show(); // 调用动态链接库提供的功能
delete pPutBox;
}
else{
AfxMessageBox("调用失败,可能是加载 FactoryDll.dll 失败或者没有找到 CreatePutBox() 接口函数!");
}
FreeLibrary(hDll);
说明:
1.为了使用方便,不要编写接口类的 .cpp 代码,如有需求,可以直接写到 .h 文件中
2.如果接口类全部定义的是纯虚方法,则需要增加一个用于析构的方法