//---------------------------15/04/08----------------------------
//builder 生成器(建造者)模式---对象创建型模式
/*
1:意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
2:动机
3:适用性:
1>当创建复杂对象的算法应该独立于该对象的组成部分以及他们的装配方式时。
2>当构造过程必须允许被构造的对象有不同的表示时。
4:结构:
Director:
builder----------------------------->Builder:
Construct() BuildPart()
{ for all objects in structure |
{ builder->BuildPart()} } |
ConcreteBuilder: - - - ->Product
BuildPart()
GetResult()
5:参与者:
1>Builder:为创建一个Product对象的各个部件指定抽象接口。
2>ConcreteBuilder:
1)实现Builder的接口以构造和装配该产品的各个部件。
2)定义并明确它所创建的表示。
3)提供一个检索产品的接口.
3>Director:构造一个使用Builder接口的对象。
4>Product:
1)表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
2)包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
6:协作:
1>客户创建Director对象,并用它所想要的Builder对象进行配置。
2>一旦产品部件被生成,导向器就会通知生成器。
3>生成器处理导向器的请求,并将部件添加到该产品中。
4>客户从生成器中检索产品。(得到产品)
下面的图说明了Builder和Director和客户的协作:
aClient aDirector aConcreteBuilder
| | |
new ConcreteBuilder---------------------------->|
new Director(aCon..)--->| |
| | |
Construct()------------>|BuildPartA()---------->|
| BuildPartB()----------->|
| BuildPartC()----------->|
| | |
GetResult()------------------------------------>|
| | |
7:效果:
1>它使你可以改变一个产品的内部表示。
Builder给Director只提供了抽象接口,隐藏了内部装配过程,所以想要改变
内部表示的时候,只需要定义一个新的Builder就行了。
2>它将构造代码和表示代码分开。
ConcreteBuilder已经提供了创建一个产品的所有代码,不同的Director可以复用它
以在相同部件集合的基础上构造不同的Product。
3>它使你可以对构造过程进行更精密的控制。
与一下子就生产产品的创建型模式不同,Builder模式是在导向者的控制下一步一步构造产品的。
所以可以更精细地控制构造过程。
8:实现:
1>要有一个抽象的Builder类为Director提供产品每一个部分创建的接口。ConcreteBuilder
只用对感兴趣的部分实现操作就行。
2>装配和构造接口:Builder类的接口必须足够普遍。
有一个需要考虑的点是,Builder创建PartB时可能需要用到PartA的对象,
所以,可以从PartA那里返回一个PartA对象,再由Director传入PartB。
3>为什么产品没有抽象类:一般生存器生成的产品的表示相差十分之大,以至于难以提供公共父类。
9:代码示例: */
//定义一个抽象类,接口都是空操作,不声明成纯虚函数是因为ConcreteBuilder只需要实现自己感兴趣的接口
class MazeBuilder
{
public:
virtual void BuildMaze(){}
virtual void BuildRoom(int room) {}
virtual void BuildDoor(int roomFrom, int roomTo){}
virtual Maze* GetMaze(){return 0;}
protected:
MazeBuilder();
};
//Director,根据传入的Builder创建迷宫
Maze* MazeGame::CreateMaze(MazeBuilder& builder)
{
//这里想怎么创建就怎么创建,无需关注底部实现细节
builder.BuildMaze();
builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor(1, 2);
return builder.GetMaze();
}
class StandardMazeBuilder : public MazeBuilder
{
public:
StandardMazeBuilder();
virtual void BuildMaze();
virtual void BuildRoom(int);
virtual void BuildDoor(int, int);
virtual Maze* GetMaze();
private:
Direction CommonWall(Room*, Room*);
Maze* _currentMaze;
};
//具体的builder
StandardMazeBuilder::StandardMazeBuilder()
{
_currentMaze = 0;
}
void StandardMazeBuilder::BuildMaze()
{
_currentMaze = new Maze;
}
Maze* StandardMazeBuilder::GetMaze()
{
return _currentMaze;
}
void StandardMazeBuilder::BuildRoom(int n)
{
if(!_currentMaze->RoomNo(n))
{
Room* room = new Room(n);
_currentMaze->AddRoom(room);
room->SetSide(North, new Wall);
room->SetSide(South, new Wall);
room->SetSide(East, new Wall);
room->SetSide(West, new Wall);
}
}
void StandardMazeBuilder::BuildDoor(int n1, int n2)
{
Room* r1 = _currentMaze->RoomNo(n1);
Room* r2 = _currentMaze->roomNo(n2);
Door* d = new Door(r1, r2);
r1->SetSide(CommonWall(r1,r2), d);
r2->SetSide(CommonWall(r2,r1), d);
}
//如果我们需要有个个会爆炸的门可以如下实现。
void StandardMazeBuilder::BuildBoomedDoor(int n1, int n2)
{
Room* r1 = _currentMaze->RoomNo(n1);
Room* r2 = _currentMaze->roomNo(n2);
Door* d = new BoomedDoor(r1, r2);
r1->SetSide(CommonWall(r1,r2), d);
// 感觉CommonWall实现为room的成员函数更好,r1.CommonWall(r2)这样更好理解
r2->SetSide(CommonWall(r2,r1), d);
}
//十分简单
Maze* maze;//Product
MazeGame game;//Director
StandardMazeBuilder builder;//Builder
game.CreateMaze(builder);
maze = builder.GetMaze();
//上面的两句可以合并成:
maze = game.CreateMaze(builder); //因为create的实现里已经调用GetMaze了
class CountingMazeBuilder : public MazeBuilder
{
public:
CountingMazeBuilder();
virtual void BuildMaze();
virtual void BuildRoom(int);
virtual void BuildDoor(int, int);
virtual void AddWall(int, Director);
void GetCounts(int&, int&) const;
private:
int _doors;
int _rooms;
};
CountingMazeBuilder::CountingMazeBuilder():_rooms(0), _doors(0)
{
//_rooms = _doors = 0; 应该使用初始化列表初始化
}
inline void CountingMazeBuilder::BuildRoom(int)
{
++_rooms;
}
inline void CountingMazeBuilder::BuildDoor(int)
{
++_doors;
}
inline CountingMazeBuilder::GetCounts(int& rooms, int& doors) const
{
rooms = _rooms;
doors = _doors;
}
//这就是一个计数的builder,感觉如果需要计数,直接放在基类里就行了, 想用的时候调用基类的方法一次就好。