我们可能会遇到这种情况,比如一个配置文件读取模块,它由几个小模块组成,每个小模块负责读取一种类型的配置.我们读取配置的顺序和过程是固定的,但是每个配置类型可能会因为业务的需求发生很多变化.
这个过程和造房子有点像.每栋楼的建造过程是差不多的,但是各个部件在每栋楼里各不相同.
有没有这样一种模式,可以帮我们应对这种复杂对象的各个部分频繁变化的需求呢?
建造者模式就是这样一种模式.它提供一种"封装机制"来隔离出"复杂对象的各个部分"的变化,从而保持系统中的"稳定构建算法"不随着需求改变而改变.其类图如下:
我们以随意构建一个拓展的字符串数组为例子,完整示例代码如下:
//////////////////////////////////////////////////////////////////
// 建造者模式 C++示例
//
// Author: 木头云
// Blog: http://darkc.at
// E-Mail: memleak@darkc.at
// Version: 1.0.814.1330(2009/08/14)
//////////////////////////////////////////////////////////////////
#include "stdafx.h"
//////////////////////////////////////////////////////////////////
// 房屋类
class CHouse : public vector<_tstring>
{
public:
void Show()
{
for( vector<_tstring>::iterator iter = this->begin(); iter != this->end(); ++iter)
{
_tcout << (*iter) << endl;
}
}
};
//////////////////////////////////////////////////////////////////
// 建造者接口类
class IBuilder abstract
{
public:
IBuilder()
{
house = new CHouse;
}
virtual ~IBuilder()
{
}
protected:
TSmartPtr<CHouse> house;
public:
virtual void BuildDoor() = 0;
virtual void BuildWall() = 0;
virtual void BuildWindows() = 0;
virtual void BuildFloor() = 0;
virtual TSmartPtr<CHouse> GetHouse()
{
return house;
}
};
// 功能建造者类
class CABuilder : public IBuilder
{
public:
void BuildDoor()
{
house->push_back(_T("A:BuildDoor"));
}
void BuildWall()
{
house->push_back(_T("A:BuildWall"));
}
void BuildWindows()
{
house->push_back(_T("A:BuildWindows"));
}
void BuildFloor()
{
house->push_back(_T("A:BuildFloor"));
}
};
class CBBuilder : public IBuilder
{
public:
void BuildDoor()
{
house->push_back(_T("B:BuildDoor"));
}
void BuildWall()
{
house->push_back(_T("B:BuildWall"));
}
void BuildWindows()
{
house->push_back(_T("B:BuildWindows"));
}
void BuildFloor()
{
house->push_back(_T("B:BuildFloor"));
}
};
class CCBuilder : public IBuilder
{
public:
void BuildDoor()
{
house->push_back(_T("C:BuildDoor"));
}
void BuildWall()
{
house->push_back(_T("C:BuildWall"));
}
void BuildWindows()
{
house->push_back(_T("C:BuildWindows"));
}
void BuildFloor()
{
house->push_back(_T("C:BuildFloor"));
}
};
//////////////////////////////////////////////////////////////////
// 指导者类
class CDirector
{
public:
static TSmartPtr<IBuilder> GetBuilder(const _tstring& strBdrName)
{
TSmartPtr<IBuilder> builder;
if( strBdrName == _T("A") )
{
builder = new CABuilder;
}
else if( strBdrName == _T("B") )
{
builder = new CBBuilder;
}
else if( strBdrName == _T("C") )
{
builder = new CCBuilder;
}
// 开始建造
Constructing(builder);
return builder;
}
static void Constructing(const TSmartPtr<IBuilder>& builder)
{
builder->BuildDoor();
builder->BuildWall();
builder->BuildWindows();
builder->BuildFloor();
}
};
//////////////////////////////////////////////////////////////////
// 主函数
int _tmain(int argc, _TCHAR* argv[])
{
CDirector::GetBuilder(_T("A"))->GetHouse()->Show(); // 建造A并显示
CDirector::GetBuilder(_T("B"))->GetHouse()->Show(); // 建造B并显示
CDirector::GetBuilder(_T("C"))->GetHouse()->Show(); // 建造C并显示
return 0;
}
//////////////////////////////////////////////////////////////////
/*
在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成.
由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定.
建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的.
它面向的是不同对象之间统一的创建或组装过程.
*/
//////////////////////////////////////////////////////////////////
代码运行结果如下:
A:BuildDoor
A:BuildWall
A:BuildWindows
A:BuildFloor
B:BuildDoor
B:BuildWall
B:BuildWindows
B:BuildFloor
C:BuildDoor
C:BuildWall
C:BuildWindows
C:BuildFloor
请按任意键继续. . .
CDirector类作为指导者,接收外部传递的参数自动控制建造者构建我们需要的产品对象.这里的CDirector::GetBuilder的内部逻辑有点类似简单工厂.
其实从上面的代码来看,建造者模式就是在工厂模式的基础上增加了一个中间的建造层,用来管理动态变化的小模块建造过程.最后生产出来的产品实际上是由各个不同小模块以相同方式拼接成的同类型大模块.那么在实际开发中,我们往往可以将CDirector与IBuilder合二为一,让IBuilder自身来管理统一的建造过程.
建造者和工厂模式之间的区别在于着重点不同.工厂模式着眼于构建相同接口但内部实现完全不同的各种对象;建造者模式着眼于构建某个内部子模块经常发生变化的稳定大模块.
更多内容请访问:http://darkc.at