将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。一个RTF(Rich Text Format)文档交换格式的阅读器应能将RTF转换为多种正文格式。该阅读器可以将RTF文档转换成普通ASCII文本或转换成一个能以交互方式编辑的正文窗口组件。但问题在于可能转换的数目是无限的。因此要能够很容易实现新的转换的增加,同时却不改变RTF阅读器。其实也就是,前面的数据接卸(源头处理)归解析,后续的显示处理,由显示处理的部分来完成。在数据解析和显示处理之间架设一个标准的桥梁,供两方通知交互。
当RTF Reader对RTF文档进行语法分析时,它使用TextConverter去做转换。无论何时RTF Reader识别了一个RTF标记(或是普通正文或是一个RTF控制字),它都发送一个请求给TextConverter去转换这个标记。TextConverter对象负责进行数据转换以及用特定格式表示该标记。至于具体转换成什么样的显示,完全有实际TextConverter来处理。
TextConvert的子类对不同转换和不同格式进行特殊处理。例如,一个ASCIIConverter只负责转换普通文本,而忽略其他转换请求。另一方面,一个TeXConverter将会为实现对所有请求的操作,以便生成一个获取正文中所有风格信息的TEX表示。一个TextWidgetConverter将生成一个复杂的用户界面对象以便用户浏览和编辑正文。
这里有个关键,就是RTF Reader解析出来的Symbol是所有TextConvert都能看的懂的,也许某个TextConvert不一定会去处理这个symbol,他有可能忽略掉这个Symbol,但忽略,也是一种看懂的行为。
参与者:
- Builder(TextConvert)
为创建一个Product对象的各个部件制定抽象接口
-
ConcreteBuilder (AsciiConverter、TeXConverter、TextWidgetConverter)
实现Builder的接口,以构造和装配该产品的各个部件
定义并明确它所创建的表示
提供一个检索产品的接口(例如, GetAsciiText和GetTextWidget)
- Director (RTFReader)
构造一个使用Builder接口的对象
- Product (AsciiText、TeXText、TextWidget)
表示被构造的复杂对象。ConcreteBuilder创建该铲平的内部表示并定义它的装配过程。
包含定义组成部件的类,包括将这些部件装配成最终产品的接口
从上图也可以看出, Builder模式除了“生成”的含义外,还强调了通过aDirector来组装所有aConcreteBuilder的过程。
class MazeBuilder { //这个是Builder public: virtual void BuildMaze() {} virtual void BuildRoom(int room) {} virtual void BuildDoor virtual Maze * GetMaze() {return 0;} protected: MazeBuilder(); }; Maze * MazeGame::CreateMaze(MazeBuilder & builder) { //这个就是Director builder.BuildMaze(); builder.BuildRoom(1); builder.BuildRoom(2); builder.BuildRoom(1, 2); return builder.GetMaze; } class StanderdMazeBuilder : public MazeBuilder { //这个是ConcreteBuilder public: StandardMazeBuilder(); virtual void BuildMaze(); virtual void BuildRoom(int); virtual void BuildDoor(int, int); virtual Maze * GetMaze(); private: Direction CommonWall(Room *, Room*); Maze * _currentMaze; }; void StandardMazeBuiler::StandardMazeBuilder() { _currentMaze = 0; } void StandardMazeBuiler::BuildMaze() { //这是ConcreteBuilder的BuilPartA _currentMaze = new Maze; }; Maze * StandardMazeBuiler::GetMaze() { //这是ConcreteBuilder的GetResult Return _currentMaze; } void StandardMazeBuiler::BuildRoom(int n) { //这是ConcreteBuilder的BuilPartB Room * room = new Room(n); room->SetSide(North, new Wall); room->SetSide(South, new Wall); room->SetSide(West, new Wall); room->SetSide(East, new Wall); _currentMaze->AddRoom(room) } //作为Client: Maze *maze; MazeGame game; //aDirector StandardMazeBuilder builder; //aConcreteBuilder Game.CreateMaze(builder); //Constructor maze = builder.GetMaze(); //getResult
3. 适用性
- 他使得你可以该表一个产品的内部表示
- 它将构造代码和表示代码分开:Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。在前面的RTF例子中,我们可以为RTF格式以外的格式定义一个阅读器,比如一个SGMLReader,并使用相同的TextConverter生成SGML文档的ASCIIText、TeXText和TextWidget译本。
- 它使你可对构造过程进行更精细的控制:Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。