1. 简介

  建造者(Builder)模式又称 生成器模式,属于创建型模式。在软件的设计中,我们可能经常会遇到需要构建某个复杂的对象(比如在游戏开发中,进行人物角色的构建),建造该对象的“过程”是稳定的(对于一个人设来都有身体,脸,发型,手脚等),而具体建造的“细节”是不同的(每个人设的身体,脸等各有千秋)。但对于用户来讲,我才不管这些,我只想告诉你,我现在需要某个对象(拥有某特征的人物角色),于是你就创建一个给我就行了。
如果你需要将一个复杂对象的 构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,“建造者(Builder)模式”,又叫生成器模式。建造者模式可以将一个产品的内部表象与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们使用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。

2. 结构

此模式的结构图如下所示:
  • Builder:是为创建一个Product对象的各个部件指定的抽象接口。
  • ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件。
  • Director:构建一个使用Builder接口的对象。
  • Product:表示被构建的复杂对象。
客户创建Director对象,并用它所想要的Builder对象进行配置;一旦产品部件被生成,导向器就会通知生成器;生成器处理导向器的请求,并将部件添加到该产品中;客户从生成器中检索产品。

3. 实例分析

考虑这么一个应用场景:例如我们正在开发某个游戏程序,其中就需要进行人物的构建。整个游戏中的人设可谓五花八门,不同的游戏场景下,需要的人设有所不同,但是这些人设的组成却是相似的过程,每个人设都需要有头部、身体、手脚等。
我们知道一个游戏的人设就是一个复杂的对象,在构建出一个人设时我们需要相应的人设的头部、发型、身体、手脚、服饰等来组成我们需要的人设。我们对人设时如何创建的过程和细节不感兴趣,我们所 需要的是指定某种类型的人设就可以得到它们。
我们仔细分析会发现,人设的建造“过程”是稳定的,都是由头部、发型、身体、手脚、服饰等来组成的,而具体建造的“细节”是不同的,每个人设都有属于自己的头部、发型、身体、手脚、服饰等。对此,自然联系到我们谈到的设计模式——建造者模式。
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  Product.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  建造者具体类
*Others:
**********************************************************************************/
#ifndef _PRODUCT_H
#define _PRODUCT_H#include <iostream>
#include <string>
#include <list>class CProudct
{
public:CProudct() { }~CProudct() { }void add(std::string strPart){m_listParts.push_back(strPart);}void show(void){std::cout << "产品创建开始---------" << std::endl;for (std::list<std::string>::iterator iter = m_listParts.begin();iter != m_listParts.end(); ++iter){std::cout << *iter << std::endl;}std::cout << "产品创建完成---------" << std::endl;}private:std::list<std::string> m_listParts;
};#endif    //#ifndef _PRODUCT_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  Builder.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  为创建一个Product对象的各个部件指定的抽象接口
*Others:
**********************************************************************************/
#ifndef _BUILDER_H
#define _BUILDER_H#include "Product.h"class CBuilder
{
public:CBuilder() { }virtual ~CBuilder() { }virtual void BuilderHead(void) = 0;virtual void BuilderBody(void) = 0;virtual void BuilderHand(void) = 0;virtual void BuilderFoot(void) = 0;virtual CProudct *GetResult(void){return NULL;}
};#endif    //#ifndef _BUILDER_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  ConcreteBuilderThin.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  具体建造者——比较瘦的人设
*Others:
**********************************************************************************/
#ifndef _CONCRETE_BUILDER_THIN_H
#define _CONCRETE_BUILDER_THIN_H#include <new>
#include "Builder.h"
#include "Product.h"class CConcreteBuilderThin    :   public CBuilder
{
public:CConcreteBuilderThin(){ try{m_pProduct = new CProudct();}catch (std::bad_alloc &ex){std::cout << "new CProudct:" << ex.what() << std::endl;abort();}}~CConcreteBuilderThin(){delete m_pProduct;}void BuilderHead(void){m_pProduct->add("一个瘦的头部形象");}void BuilderBody(void){m_pProduct->add("一个瘦的身体形象");}void BuilderHand(void){m_pProduct->add("一个瘦的手臂形象");}void BuilderFoot(void){m_pProduct->add("一个瘦的腿部形象");}CProudct *GetResult(void){return m_pProduct;}private:CProudct *m_pProduct;
};#endif    //#ifndef _CONCRETE_BUILDER_THIN_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  ConcreteBuilderFat.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  具体建造者——比较胖的人设
*Others:
**********************************************************************************/
#ifndef _CONCRETE_BUILDER_FAT_H
#define _CONCRETE_BUILDER_FAT_H#include <new>
#include "Builder.h"
#include "Product.h"class CConcreteBuilderFat : public CBuilder
{
public:CConcreteBuilderFat(){try{m_pProduct = new CProudct();}catch (std::bad_alloc &ex){std::cout << "new CProudct:" << ex.what() << std::endl;abort();}}~CConcreteBuilderFat(){delete m_pProduct;}void BuilderHead(void){m_pProduct->add("一个胖的头部形象");}void BuilderBody(void){m_pProduct->add("一个胖的身体形象");}void BuilderHand(void){m_pProduct->add("一个胖的手臂形象");}void BuilderFoot(void){m_pProduct->add("一个胖的腿部形象");}CProudct *GetResult(void){return m_pProduct;}private:CProudct *m_pProduct;
};#endif    //#ifndef _CONCRETE_BUILDER_FAT_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  Director.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  指挥者
*Others:
**********************************************************************************/
#ifndef _DIRECTOR_H
#define _DIRECTOR_H#include "Builder.h"class CDirector
{
public:CDirector() { }~CDirector() { }void Construct(CBuilder *pBuilder){if (pBuilder){pBuilder->BuilderHead();pBuilder->BuilderBody();pBuilder->BuilderHand();pBuilder->BuilderFoot();}}
};#endif    //#ifndef _DIRECTOR_H
/*********************************************************************************
*Copyright(C),Your Company
*FileName:  Director.h
*Author:  Huangjh
*Version:
*Date:  2017-10-29
*Description:  创建者模式测试用例
*Others:
**********************************************************************************/
#include "Director.h"
#include "ConcreteBuilderFat.h"
#include "ConcreteBuilderThin.h"int main(void)
{CProudct *pPruduct;CDirector *pDirector = new CDirector();CBuilder *pThinPeople = new CConcreteBuilderThin();CBuilder *pFatPeople = new CConcreteBuilderFat();pDirector->Construct(pThinPeople);pPruduct = pThinPeople->GetResult();pPruduct->show();pDirector->Construct(pFatPeople);pPruduct = pFatPeople->GetResult();pPruduct->show();return 0;
}

运行结果如下所示:

产品创建开始---------
一个瘦的头部形象
一个瘦的身体形象
一个瘦的手臂形象
一个瘦的腿部形象
产品创建完成---------
产品创建开始---------
一个胖的头部形象
一个胖的身体形象
一个胖的手臂形象
一个胖的腿部形象
产品创建完成---------

4. 优缺点

4.1 优点

  • 它使你可以改变一个产品的内部表示。Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品实如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。
  • 它将构造代码和表示代码分离。Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部的类的所有信息;这些类是不出现在Builder接口中的。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构造不同的Product。
  • 它使你可对构造过程进行更精细的控制。Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品时向导者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反应产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

4.2 缺点

  • 建造者模式所创建的产品一般具有相似的过程,如果产品之间差异性很大,则不适合使用建造者模式,因此其应用有限。
  • 如果产品内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很复杂。

5. 应用场景

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

6. 参考

  • 《大话设计模式》
  • 《设计模式——可复用面向对象软件的基础》

设计模式——生成器(建造者)模式相关推荐

  1. Java设计模式(建造者模式-适配器模式-桥接模式)

    Java设计模式Ⅲ 1.建造者模式 1.1 建造者模式概述 1.2 建造者模式的注意事项和细节 1.3 代码理解 2.适配器模式 2.1 类适配器模式 2.1.1 代码理解 2.2 对象适配器模式 2 ...

  2. java设计模式 建造模式_理解java设计模式之建造者模式

    理解java设计模式之建造者模式 发布于 2020-12-10| 复制链接 摘记: 建造者模式(Builder Pattern)主要用于"分步骤构建一个复杂的对象",在这其中&qu ...

  3. C#设计模式之四建造者模式(Builder Pattern)【创建型】

    一.引言 今天我们要讲讲Builder模式,也就是建造者模式,当然也有叫生成器模式的,英文名称是Builder Pattern.在现实生活中,我们经常会遇到一些构成比较复杂的物品,比如:电脑,它就是一 ...

  4. 学习《图说设计模式》建造者模式

    图说设计模式之建造者模式 1. 模式动机 无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮.方向盘.发送机等各种部件.而对于大多数用户而言,无须知道这 ...

  5. 实践GoF的23种设计模式:建造者模式

    本文分享自华为云社区<[Go实现]实践GoF的23种设计模式:建造者模式>,作者: 元闰子. 简述 在程序设计中,我们会经常遇到一些复杂的对象,其中有很多成员属性,甚至嵌套着多个复杂的对象 ...

  6. java设计模式之建造者模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  7. python设计模式之建造者模式

    python设计模式之建造者模式 ​ 建造者模式的适用范围:想要创建一个由多个部分组成的对象,而且它的构成需要一步接一步的完成.只有当各个部分都完成了,这个对象才完整.建造者模式表现为复杂对象的创建与 ...

  8. D5:C#设计模式之四建造者模式(Builder Pattern)【创建型】

    一.引言 今天我们要讲讲Builder模式,也就是建造者模式,当然也有叫生成器模式的,英文名称是Builder Pattern.在现实生活中,我们经常会遇到一些构成比较复杂的物品,比如:电脑,它就是一 ...

  9. 建造者模式java_java设计模式3——建造者模式

    java设计模式3--建造者模式 1.建造者模式介绍: 建造者模式属于创建型模式,他提供了一种创建对象得最佳方式 定义: 将一个复杂对象的构建和与它的表示分离,使得同样的构建过程可以创建不同的表示 主 ...

  10. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

最新文章

  1. 个人电脑详细的安全设置方法之一
  2. Linux-Shell基础(变量,字符串,数组)
  3. 今年电子设计竞赛取消了?
  4. Solve The Maze CodeForces - 1365D(贪心+dfs)
  5. HTTP 协议(详解)
  6. 红黑树与平衡二叉树_百图详解红黑树,想不理解都难
  7. NAND FLASH读写原理
  8. Dart 语言不如 Kotlin?这里列了 13 个原因
  9. 安卓java代码写控件_安卓自定义流程进度图控件实例代码
  10. 离散数学第六版第er章偶数题答案_离散数学答案(尹宝林版)第二章习题解答
  11. 图片放大以后不清晰怎么办?
  12. 吴伯凡-认知方法论-如何增加自己认知的维度
  13. MacBook Air 2013全新安装Win7
  14. Mac系统下MySQLWorkbench出现no connection established问题
  15. 系统集成项目管理工程师2021年下半年下午案例分析题及答案
  16. html地址欄小圖標,网站地址栏前面的小图标favicon.ico制作方法
  17. 云计算系统运用了许多技术,最主要的核心技术是什么
  18. android 双SIM卡检测是否可用和信号强度
  19. MATLAB中.mat文件转为excel(.xlsx)
  20. Hadoop大数据开发基础项目化教程

热门文章

  1. 阿拉丁微信小程序创新论坛“上海站”成功举办 携多位业界专家探讨小程序创投机会...
  2. BOSHIDA 模块电源的详细分类
  3. 概率机器人:测距传感器的波束模型
  4. iOS上用GPUImage给视频加滤镜
  5. call()和apply()及bind( )三者的相同与区别
  6. 单点登录简要介绍及分析
  7. c++函数 十进制转换成二进制
  8. 【对讲机的那点事】手把手教你玩转特易通TH-F8对讲机恢复出厂设置
  9. 又出新玩意,还是网易云音乐会玩
  10. CSDN日报20170513 ——《腾讯2017校招实习生面试总结》