意图

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以表示不同的表示。

适用性

  • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  • 当构造过程必须允许被构造的对象有不同的表示时。

UML图

  • Builder ——为创建一个Product对象的各个部件指定抽象接口。
  • ConcreteBuilder ——实现Builder的接口以构造和装配该产品的各个部件。

    ——定义并明确它所创建的表示。

    ——提供一个检索产品的接口。

  • Director ——构造一个使用Builder接口的对象。
  • Product ——表示被构造的复杂对象。
  • ConcreteBuilder创建该产品的内部表示并定义它的装配过程。

    ——包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

代码示例

  ConcreteBuilder中需要提供构建产品的的各个部件的函数,以及对外获取被创建产品的接口。还是以创建迷宫为例,迷宫产品组件包括迷宫自身、房间、门,这些组件创建函数(BuildPart)需定义为虚函数,以便子类继承实现。在产品各部分创建好了后,需要通过对外的接口GetResult来获取创建的产品,本例GetMaze返回创建的迷宫。

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();
};

  因为builder中BuildPart和GetResult函数都是虚函数,所以Director并不关心继承Builder的子类实现,Director只需要按部就班的调用Builder的BuildPart函数来创建产品,如下例:

builder.BuildMaze();//创建迷宫

builder.BuildRoom(1);//创建1号房间

builder.BuildRoom(2);//创建2号房间

builder.BuildDoor(1,2);//创建1号房间和2号房间的门

在产品各个部件创建完成后,调用:

build.GetMaze();//获取已创建迷宫

Maze* MazeGame::CreateMaze(MazeBuilder& builder){
builder.BuildMaze(); builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor(1,2); return builder.GetMaze();
}
MazeBuilder基类提供实现产品的接口,具体实现还需要子类来实现。这里StandardMazeBuilder继承MazeBuilder并实现了基本功能。
StandardMazeBuilder类声明:
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;
}

StandardMazeBuilder类实现:

#include "Builder.h"

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);
}

   在实现了Director和Builder后,Client无需关心具体产品的具体实现,只需要新建该Builder类,传递给Director,就能创建出不同的产品了。

#include "Direcotr.h"
#include "StandardMazeBuilder.h" int Main(){ Maze *maze;
MazeGame game;
StandardMazeBuilder builder; game.CreateMaze(builder);
maze = builder.GetMaze();
return 0;
}

 

优缺点

优点:

  • 将一个复杂对象的创建过程封装起来。
  • 允许对象通过多个步骤来创建,并且可以改变过程(这和只有一个步骤的工厂模式不同)。
  • 向客户隐藏产品内部的实现。
  • 产品的实现可以被替换,因为客户只看到一个抽象的接口。

缺点:

  • 与工厂模式相比,采用生成器创建对象的模式,需要具备更多的领域知识。

参考文献:

GOF《设计模式》

《Head First设计模式》

设计模式之生成器(Builder)模式的更多相关文章

  1. 设计模式 笔记 生成器(建造者)模式 Builder

    //---------------------------15/04/08---------------------------- //builder 生成器(建造者)模式---对象创建型模式 /* ...

  2. Builder模式在Java中的应用

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  3. Builder模式(建造者模式)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  4. Builder模式在Java中的应用(转)

    在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...

  5. 每天一个设计模式-7 生成器模式(Builder)

    每天一个设计模式-7 生成器模式(Builder) 一.实际问题 在讨论工厂方法模式的时候,提到了一个导出数据的应用框架,但是并没有涉及到导出数据的具体实现,这次通过生成器模式来简单实现导出成文本,X ...

  6. 设计模式03: Builder 生成器模式(创建型模式)

    Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...

  7. 设计模式十: 生成器模式(Builder Pattern)

    简介 生成器模式属于创建型模式的一种, 又叫建造者模式. 生成器模式涉及4个关键角色:产品(Product),抽象生成器(builder),具体生成器(ConcreteBuilder),指挥者(Dir ...

  8. 面向对象设计模式纵横谈:Builder 生成器模式(笔记记录)

    Builder模式的缘起 假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化. 如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正…… 动 ...

  9. 设计模式之构建者模式(Builder):初步理解

    构建者(Builder)设计模式(又叫生成器设计模式): 当一个类的内部数据过于复杂的时候(通常是负责持有数据的类,比如Config.VO.PO.Entity...),要创建的话可能就需要了解这个类的 ...

随机推荐

  1. WEB开发-动态验证码

    1.基于Python实现,用到了django后台处理,刷新验证码功能,其他语言大同小异 2.登录界面 login.html <!DOCTYPE html> <html lang=&q ...

  2. java异常处理、多态

    第一:GC是什么? 为什么要有GC?  第二:垃圾回收的优点和原理.并考虑2种回收机制.  第三:垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?  第 ...

  3. 追溯 React Hot Loader 的实现

    文:萝卜(沪江金融前端开发工程师) 本文原创,转载请注明作者及出处 如果你使用 React ,你可以在各个工程里面看到 Dan Abramov 的身影.他于 2015 年加入 facebook,是 R ...

  4. linux系统/sbin/init执行过程

    对于Linux的启动过程,之前一直都是研究到内核运行/sbin/init,启动第一个用户进程为止,因为这部分一直都是在内核态工作,所以对于学习内核还是有帮助的,当时/sbin/init之后的过程也需要 ...

  5. 关于编译FFMPEG的初级教程

    首先我们要下载相关工具,这里不多说,大家按照我的地址去下载文件就好了 MINGW下载地址:http://prdownloads.sourceforge.net/mingw/MinGW-3.1.0-1. ...

  6. 基于DirectShow的MPEG-4视频传输系统的研究与实现

    1 引言     近年来,随着国民经济的发展,社会各个部门对于视频监视系统的需求越来越多.但目前的很多监视系统都跟具体的硬件相关,必须要具体的采集卡的支持才能实现.所以有必要开发一种具有通用性的视频监 ...

  7. apache配置,禁止ip访问web站点

    由于一台服务器上面部署了好几个应用,对应不同的域名,如果用户知道ip地址的话,直接用户ip地址访问,会显示第一个虚拟主机的页面(更改了虚拟主机的顺序,每次都是显示第一个).这样对用户造成不好的印象,所 ...

  8. (二十八)monggodb和maven零散笔记

    (1)maven导包的问题:当在pom.xml界面的Dependencies中点击add之后输入jar包查询条件后,如果确定条件没有输错,repo中也确实存在相关jar包,而并没有查处任何结果时,可以 ...

  9. Linux显示inode的信息

    Linux显示inode的信息 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ df -i 文件系统 Inode 已用(I) 可用(I) 已用(I)% 挂载点 ...

  10. TreeNode.trage的使用

    对于trage的使用 msdn是这样解释的 TreeNode.Target 属性 .NET Framework 2.0 其他版本 注意:此属性在 .NET Framework 2.0 版中是新增的. ...