将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表示,即内部构成组件不同但是构建方法相同的一些对象。
Builder 生成器
- 为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder
- 实现Builder的接口以构造和装配产品的各个部件。
- 定义并明确它所创建产品的表示。
- 提供一个返回产品的接口。
Director导向器
- 构造一个使用Builder接口的对象
- 引导生成器构造产品对象
Product产品对象
- 表示被构造的复杂对象。ConcreteBuilder负责创建该产品的内部构件并定义它的装配过程。
- 包含定义好的组成部件的类,包含将这些部件装配成最终产品的接口。
1)使你可以改变一个产品的内部表示
Builder对象提供给Director一个构造产品的抽象接口。该接口使得生成器可以隐藏产品的内部结构。它同时隐藏了给产品是如何装配而成的。同样由于产品是通过抽象接口生成的,在需要改变产品的内部结构时只需要定义一个新的生成器。
2)将构造代码和表示代码分开
Builder模式通过封装一个复杂的构造和表示方法提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息,即这些类不出现在Builder接口中。每个ConcreteBuilder包含创建和装配一个特定产品的所有代码,不同的Director可以复用它来创建基于相同产品内部构件集合不同的Product。
3)它使得可以对产品构造过程进行更精细的控制
Builder模式和一下子就生成产品的创建型模式不同,它是在导向器的控制下一步一步构造产品的。仅当该产品完成时导向者才藏生成器中取回它。因此Builder接口能更好的反映产品的构造过程。这使得可以更精细的控制构造过程,从而能更精细的控制所得产品的内部结构。
通常有一个抽象的Builder类为导向器要求的每个构件定义一个操作接口。这些接口缺省什么都不做,而ConcreteBuilder类对它有兴趣的创建的构建重定义这些接口。
1)装配和构造接口
生成器逐步的构造它们的产品,因此Builder类接口必须足够普遍以便为各种类型的具体生成器构造产品提供接口。
2)产品没有抽象类
通常情况下,由具体生成器生成的产品,即使导向器相同,它们的表示可能相差也会比较大,以至于公共父类是没有意义的。并且通常不需要产品的公共接口,因为客户通常用合适的具体生成器来配置导向器,客户处于的位置使它知道Builder的哪一个子类被使用,然后相应的处理它的产品。
3)在Builder类中缺省方法为空
C++中生成方法故意不声明为纯虚成员函数,而是把它们定义为空方法,这使得ConcreteBuilder只重定义它们所感兴趣的操作即可。
//MazeBuilder.hpp
//定义生成器
#pragma once
#include "Maze.hpp"
//抽象Builder类
//定义创建产品内部部件的接口
class MazeBuilder
{
public:
virtual void BuildMaze() { }
virtual void BuildRoom(int n) { }
virtual void BuildDoor(int roomFrom, int roomTo) { }
virtual Maze* GetMaze()
{
return nullptr;
}
protected:
MazeBuilder() {}
};
//标准的迷宫生成器,使用普通迷宫原料
class StandardMazeBuilder : public MazeBuilder
{
public:
StandardMazeBuilder() : MazeBuilder()
{
std::cout << "new StandardMazeBuilder" << std::endl;
m_currentMaze = nullptr;
}
virtual void BuildMaze()
{
m_currentMaze = new Maze();
}
virtual void BuildRoom(int n)
{
//这个编号的房间之前不存在
if (!m_currentMaze->RoomNo(n))
{
Room* room = new Room(n);
m_currentMaze->AddRoom(room);
room->SetSide(North, new Wall());
room->SetSide(South, new Wall());
room->SetSide(East, new Wall());
room->SetSide(West, new Wall());
}
}
virtual void BuildDoor(int n1, int n2)
{
Room* r1 = m_currentMaze->RoomNo(n1);
Room* r2 = m_currentMaze->RoomNo(n2);
Door* d = new Door(r1, r2);
r1->SetSide(CommonWall(r1, r2), d);
r2->SetSide(CommonWall(r2, r1), d);
}
virtual Maze* GetMaze()
{
return m_currentMaze;
}
private:
// 生成两个房间之间公共墙壁的方位
Direction CommonWall(Room* r1, Room* r2)
{
return North;
}
Maze* m_currentMaze;
};
//另一个具体生成器,生成一个对导向器进行计数的产品
class CountingMazeBuilder : public MazeBuilder
{
public:
CountingMazeBuilder()
{
std::cout << "new CountingMazeBilder" << std::endl;
m_room = m_door = 0;
}
virtual void BuildRoom(int)
{
m_room++;
}
virtual void BuildDoor(int, int)
{
m_door++;
}
void GetCounts(int& rooms, int& doors) const
{
rooms = m_room;
doors = m_door;
}
private:
int m_room;
int m_door;
};
//MazeGame.hpp
//迷宫游戏, 使用不同的导向器产生不同类型的迷宫
#pragma once
#include "Maze.hpp"
#include "MazeBuilder.hpp"
class MazeGame
{
public:
//导向器Director,引导生成器生成产品,即定义产品的生成步骤
Maze* CreateMaze(MazeBuilder& builder)
{
builder.BuildMaze();
builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor(1, 2);
return builder.GetMaze();
}
//使用相同生成器的另一个导向器,生成过程可以不同
//因此可以构建出基于相同产品部件集合的不同产品
//即由相同Room,Door构成的不同Maze
Maze* CreateComplexMaze(MazeBuilder& builder)
{
builder.BuildMaze();
for (int i = 0; i < 100; i++)
{
builder.BuildRoom(i);
}
return builder.GetMaze();
}
};
//main.cpp
//使用不同方法创建迷宫
#include "MazeGame.hpp"
int main()
{
Maze* maze;
MazeGame game;
StandardMazeBuilder builder1;//具体生成器,选择不同的生成器,产品构件就会不同
game.CreateMaze(builder1);//导向器,选择不同的导向器,产品的生成过程就会不同
maze = builder1.GetMaze();//客户直接从具体生成器获得产品
// ...
//另一个使用ConutingMazeBuilder的客户
int rooms, doors;
CountingMazeBuilder builder2; //选择不同的生成器,内部构件不同
game.CreateMaze(builder2); //相同的导向器,因此会有相同的内部结构
builder2.GetCounts(rooms, doors);// 故这里rooms和doors可以指示所有使用CreateMaze导向器的Maze的情况
std::cout << "The Maze has "
<< rooms << " rooms and "
<< doors << " doors" << std::endl;
return 0;
}
# 输出
new StandardMazeBuilder
new Maze
new Room with number 1
Maze add room 1
new Wall
Set Room 1 North Side with a Wall
new Wall
Set Room 1 South Side with a Wall
new Wall
Set Room 1 East Side with a Wall
new Wall
Set Room 1 West Side with a Wall
new Room with number 2
Maze add room 2
new Wall
Set Room 2 North Side with a Wall
new Wall
Set Room 2 South Side with a Wall
new Wall
Set Room 2 East Side with a Wall
new Wall
Set Room 2 West Side with a Wall
new Door with room 1 and room 2
Set Room 1 North Side with a Door
Set Room 2 North Side with a Door
new CountingMazeBilder
The Maze has 2 rooms and 1 doors
Abstract Factory抽象工厂模式和Builder模式很像,因为它们都可以创建复杂对象。主要区别是Builder模式注重于一步步构造一个复杂对象,客户最后得到是一个复杂对象。而Abstract Factory注重于多个系列的产品对象,客户对这个产品系列中的所有产品都知晓。Builder在最后一步返回产品,而Abstract Factory是立即返回的。
还有一个Composite组合模式产品,通常是用Builder生成的。