设计模式之生成器(Builder)模式
意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以表示不同的表示。
适用性
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
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)模式的更多相关文章
- 设计模式 笔记 生成器(建造者)模式 Builder
//---------------------------15/04/08---------------------------- //builder 生成器(建造者)模式---对象创建型模式 /* ...
- Builder模式在Java中的应用
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式(建造者模式)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Builder模式在Java中的应用(转)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- 每天一个设计模式-7 生成器模式(Builder)
每天一个设计模式-7 生成器模式(Builder) 一.实际问题 在讨论工厂方法模式的时候,提到了一个导出数据的应用框架,但是并没有涉及到导出数据的具体实现,这次通过生成器模式来简单实现导出成文本,X ...
- 设计模式03: Builder 生成器模式(创建型模式)
Builder生成器模式(创建型模式) Builder模式缘起假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分富于变化.如果使用最直观的设计方法,每个房屋部分的变化,都将 ...
- 设计模式十: 生成器模式(Builder Pattern)
简介 生成器模式属于创建型模式的一种, 又叫建造者模式. 生成器模式涉及4个关键角色:产品(Product),抽象生成器(builder),具体生成器(ConcreteBuilder),指挥者(Dir ...
- 面向对象设计模式纵横谈:Builder 生成器模式(笔记记录)
Builder模式的缘起 假设创建游戏中的一个房屋House设施,该房屋的构建由几个部分组成,且各个部分要富于变化. 如果使用最直观的设计方法,每一个房屋部分的变化,都将导致房屋构建的重新修正…… 动 ...
- 设计模式之构建者模式(Builder):初步理解
构建者(Builder)设计模式(又叫生成器设计模式): 当一个类的内部数据过于复杂的时候(通常是负责持有数据的类,比如Config.VO.PO.Entity...),要创建的话可能就需要了解这个类的 ...
随机推荐
- 快了快了,你的 MacBook Pro 和 FineUICore!
着玻璃窗,看到星巴克里那帮人拿着MacBook喝咖啡,你是不是要默念一遍:这帮傻叉,就爱装逼! 不过话说回来,你想不想尝试下这个傻叉的感觉? 是时候了,给自己一个理由,拥有自己的 MacBook Pr ...
- hive: insert数据时Error during job, obtaining debugging information 以及beyond physical memory limits
insert overwrite table canal_amt1...... 2014-10-09 10:40:27,368 Stage-1 map = 100%, reduce = 32%, Cu ...
- linux 搭建CA服务器 http+ssl mail+ssl 扫描与抓包
搭建CA服务器 CA服务是给服务器发放数字证书,被通信双方信任,独立的第三方机构 国内常见的CA机构 中国金融认证中心(CFCA) 中国电信安全认证中心(CTCA) 北京数字证书认证中心(BJCA) ...
- Netty的并发编程实践2:volatile的正确使用
长久以来大家对于volatile如何正确使用有很多的争议,既便是一些经验丰富的Java设计师,对于volatile和多线程编程的认识仍然存在误区.其实,volatile的使用非常简单,只要理解了Jav ...
- (二十)java小练习二
练习4:定义一个整数数组,编写程序求出一个数组的基数和偶数个数 package demo; /* * 定义一个整数数组,编写程序求出一个数组的基数和偶数个数 */ public class Tes ...
- freemarker.core.InvalidReferenceException
1.错误描述 freemarker.core.InvalidReferenceException:on line 68,column 18 in ftl/inc/incPro.ftl p.mainSe ...
- 【原】Java学习笔记030 - 异常
package cn.temptation; public class Sample01 { public static void main(String[] args) { /* * 异常:Java ...
- 使用promise方式写settimeout
//使用promise方式写settimeout, //好处就是用于写动画的时候只需知道后一个的动画在前一个动画结束后多久执行 console.time('settimeout:');//开始计算这段 ...
- 异常-----java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.core.KeyFactory
SSH 类库问题 java.lang.NoClassDefFoundError: Could not initialize class net.sf.cglib.proxy.Enhancer2009- ...
- 【原】从零开始改造淘淘商城(引入dubbo解决项目耦合)02
前言: 关于为什么要引入dubbo框架,而不是用spring cloud或者是motan呢,主要是笔者现在公司用的就是dubbo,并且第一次接触到微服务的概念是来源于dubbo,再加上最近dubbo频 ...