一、定义

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

建造者模式的基本思想是使用简单对象一步步构建一个复杂的对象。属于创建型模式。

建造者模式更关注各对象的组装过程,实现各个部件相互独立,并组装为复杂整体的作用。

二、建造者模式实例

每逢中秋,各商家都会生产出带有各种包装,用于各种场合的月饼产品。因为月饼产品除了月饼不可或缺外,由于使用场景不同,客户可能对产品的包装有不同的需求,这就导致“构建”月饼产品十分的复杂。

我们以“构建”这样的月饼产品为例。首先,我们假设我们的产品可能需要下列部件:

月饼(需要明确口味)、内包装、外包装、礼品袋。即具有这些成员的月饼类

class Mooncake
{string _filling;           //月饼口味string _innerPackaging;      //内包装string _outerPackaging;    //外包装string _giftBags;          //礼品袋包装
}

对于目标:构建出一件月饼产品,我们有如下方法

1、折叠式构造方法

定义一批构造函数,覆盖对必选和可选部件的组合,在构造时确认组装产品的部件

//折叠式构造方式
class Mooncake
{
public:Mooncake(string filling) : _filling(filling) {}Mooncake(string filling, string innerPackaging) : _filling(filling), _innerPackaging(innerPackaging) {}Mooncake(string filling, string innerPackaging, string outerPackaging) : _filling(filling), _innerPackaging(innerPackaging), _outerPackaging(outerPackaging) {}Mooncake(string filling, string innerPackaging, string outerPackaging, string giftBags) : _filling(filling), _innerPackaging(innerPackaging), _outerPackaging(outerPackaging), _giftBags(giftBags) {}//...这还不止,还需要其他组合。例如_filling + _outerPackaging的。以下都省略
private:string _filling;           //月饼口味(必选)string _innerPackaging;     //内包装string _outerPackaging;    //外包装string _giftBags;          //礼品袋包装
};int main()
{//内包装为纸盒的五仁馅月饼产品Mooncake *moonCake = new Mooncake("五仁",“纸盒”);
}

2、对外暴露部件设置,使各部件可以构造后再设置

class Mooncake
{
public:Mooncake() :_filling(""),_innerPackaging(""),_outerPackaging(""),_giftBags("") {}virtual ~Mooncake() {}//內馅在子类实现确认void SetFilling(string param){_filling = param;}void SetInnerPackaging(string param){_innerPackaging = param;}void SetOuterPackaging(string param){_outerPackaging = param;}void SetGiftBags(string param){_giftBags = param;}protected:string _filling;           //月饼口味string _innerPackaging;      //内包装string _outerPackaging;    //外包装string _giftBags;          //礼品袋包装
};int main()
{Mooncake *moonCake = new Mooncake();moonCake -> SetFilling("五仁");moonCake -> SetOuterPackaging("一次性方便袋");
}

但是上述2都有些显然的缺点。

使用方法1的构造函数要时刻注意传参的顺序是否错误,因为一旦传参太多,容易造成混乱,对可读性也不是很友好。而且一旦构建的可能组合太多,会需要大量构造函数。

使用方法2,虽然可以很方便地传入正确参数,将“部件”设置正确,也足够灵活。但是对象中的属性是分步设置的,在没有构建完成时,产品对象就已经对外暴露了,容易发生错误。

对于以上需求,我们可以用建造者模式解决。

3、建造者模式的实现

1)月饼产品类,提供对外设置属性的接口,但是和2方法不同

class Mooncake
{
public:Mooncake() :_filling(""),_innerPackaging(""),_outerPackaging(""),_giftBags("") {}virtual ~Mooncake() {}//內馅在子类实现确认void SetFilling(string param){_filling = param;}void SetInnerPackaging(string param){_innerPackaging = param;}void SetOuterPackaging(string param){_outerPackaging = param;}void SetGiftBags(string param){_giftBags = param;}void Introduce(){cout << "这款月饼是" << _filling << "馅的" << endl;if ("" != _innerPackaging){cout << "内包装采用" << _innerPackaging << endl;}else{cout << "无内包装" << endl;}if ("" != _outerPackaging){cout << "外包装采用" << _outerPackaging << endl;}else{cout << "无外包装" << endl;}if ("" != _giftBags){cout << "具有" << _giftBags << "的礼品袋" << endl;}cout << "您看是否符合您的需求。" << endl;}
protected:string _filling;           //月饼口味string _innerPackaging;     //内包装string _outerPackaging;    //外包装string _giftBags;          //礼品袋包装
};

2)构建者抽象类,声明构建月饼产品的接口,用于规范化产品的构建,一般由子类具体实现构建方法

class Builder
{
public:virtual ~Builder() {}virtual void buildFilling() = 0;                     //构建內馅virtual void buildInnerPackaging(string param) = 0;  //构建内包装virtual void buildOuterPackaging(string param) = 0;  //构建外包装virtual void buildGiftBags(string param) = 0;        //构建礼品袋virtual Mooncake* build() = 0;                               //对外提供构建的对象的指针
protected:Mooncake *_moonCake;              //待构建的对象指针
};

3)构建者具体类-五仁月饼构建者(filling属性可以确认),可以具体实现对目标对象的构建

class FiveNutsMooncakeBuilder :public Builder
{
public:FiveNutsMooncakeBuilder(){_moonCake = new Mooncake();}~FiveNutsMooncakeBuilder(){if (nullptr != _moonCake){delete _moonCake;_moonCake = nullptr;}}void buildFilling(){if (nullptr != _moonCake){_moonCake->SetFilling("五仁");}}void buildInnerPackaging(string param){if (nullptr != _moonCake){_moonCake->SetInnerPackaging(param);}}void buildOuterPackaging(string param){if (nullptr != _moonCake){_moonCake->SetOuterPackaging(param);}}void buildGiftBags(string param){if (nullptr != _moonCake){_moonCake->SetGiftBags(param);}}Mooncake* build(){return _moonCake;}
};

4)指挥者类,传入构建者对象,指挥构建者对产品的构建过程。在这个案例中,我写了两种组建方案:简单包装和精美包装。虽然里面的月饼可能是相同的产品,但是大家都知道这肯定是2种价格~

class Director
{
public:Director(Builder* bd) :_builder(bd) {}~Director(){if (nullptr != _builder){delete _builder;_builder = nullptr;}}//简单包装的月饼产品Mooncake* SimplePackaging(){if (nullptr != _builder){_builder->buildFilling();_builder->buildOuterPackaging("纸盒");return _builder->build();}}//精美包装的月饼产品Mooncake* GiftPackaging(){if (nullptr != _builder){_builder->buildFilling();_builder->buildInnerPackaging("纸盒");_builder->buildOuterPackaging("精美铁盒");_builder->buildGiftBags("礼品袋");return _builder->build();}}private:Builder* _builder;
};

5)使用

int main(int argc, char *argv[])
{Builder *builder = new FiveNutsMooncakeBuilder();Director *direstor = new Director(builder);cout << "顾客A:" << endl;//获取已经“建造”好的月饼产品Mooncake* moonCakeA = direstor->GiftPackaging();//输出介绍话术moonCakeA->Introduce();system("pause");return 0;
}

6)这样构建的产品对象,方便扩展。假如想要增加别的月饼产品,比如增加什锦月饼。则我们就可以新增一个构建者。

class MixedMooncakeBuilder :public Builder
{
public:MixedMooncakeBuilder(){_moonCake = new Mooncake();}~MixedMooncakeBuilder(){if (nullptr != _moonCake){delete _moonCake;_moonCake = nullptr;}}void buildFilling(){if (nullptr != _moonCake){_moonCake->SetFilling("什锦");}}void buildInnerPackaging(string param){if (nullptr != _moonCake){_moonCake->SetInnerPackaging(param);}}void buildOuterPackaging(string param){if (nullptr != _moonCake){_moonCake->SetOuterPackaging(param);}}void buildGiftBags(string param){if (nullptr != _moonCake){_moonCake->SetGiftBags(param);}}Mooncake* build(){return _moonCake;}
};

三、总结

1、优缺点

该模式的主要优点如下:

1)封装性好,构建和表示分离;

2)扩展性好,各个具体的建造者相互独立,有利于系统的解耦;

3)客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。

其缺点如下:

1)产品的组成部分必须相同,这限制了其使用范围。

2)如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

2、建造者模式的适用场景

1、需要构建的对象相对复杂,具有多个属性,并且有些属性具有默认值;

2、相同的方法,不同的执行顺序,产生不同的结果;

3、多个部件,可以装配到一个对象中,但是不同组合产生的结果又不相同;

创建的产品具备复杂创建过程时,可以抽取出共性创建过程,然后交由指挥者类自定义创建流程,使得同样的创建行为可以(传入不同构建者)生产出不同的产品,分离了创建与表示,使创建产品的灵活性大大增加。

【参考&致谢】

设计模式之建造者(Builder)模式 | 菜鸟教程 (runoob.com)https://www.runoob.com/w3cnote/builder-pattern.html建造者模式(Bulider模式)详解 (biancheng.net)http://c.biancheng.net/view/1354.html

设计模式-建造者模式C++相关推荐

  1. Python设计模式-建造者模式

    Python设计模式-建造者模式 代码基于3.5.2,代码如下; #coding:utf-8 #建造者模式 class Burger():name = ""price = 0.0d ...

  2. 说说设计模式~建造者模式(Builder)

    建造者模式是我的"设计模式"里创建型模式里的最后一篇,这种模式在实现中,很多架构都用到了,如MVC,MVP,MVVM,它们都是有建造者模式的精髓的,即,创建与表现分享,我们的MVC ...

  3. 设计模式 建造者模式_设计模式:建造者

    设计模式 建造者模式 有时需要在应用程序中创建一个复杂的对象. 一种解决方案是Factory模式,另一种是Builder设计模式. 在某些情况下,您甚至可以结合使用这两种模式. 但是在本文中,我想研究 ...

  4. 设计建造者模式java代码,Java设计模式-建造者模式

    定义 Separate the construction of a complex object from its representation so that the sameconstructio ...

  5. python创造者_python 设计模式-建造者模式

    问题:在上一篇python设计模式:抽象工厂模式中,我们尝试用抽象工厂模式规范化了 Pizza 原材料的供应以及 Pizza 的创建.但是我们忽略了一个问题,那就是每种 Pizza 的烘焙时间依赖于生 ...

  6. java设计模式-建造者模式

    概念:使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. ...

  7. 设计模式-建造者模式(转自:http://www.cnblogs.com/cbf4life/archive/2010/01/14/1647710.html)...

    11.1 变化是永恒的 又是一个周三,快要下班了,老大突然拉住我,喜滋滋地告诉我:"牛叉公司很满意我们做的模型,又签订了一个合同,把奔驰.宝马的车辆模型都交给我们公司制作了,不过这次又额外增 ...

  8. 大话设计模式—建造者模式

    建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 一个 Builder 类会一步一步构造最 ...

  9. 我的Java设计模式-建造者模式

    在未上大学之前,一直有个梦想"I have a dream!",就是能成为一位汽车工程师,一直幻想着开着自己设计的汽车飞奔在公路上,迷倒了万千少女.咳咳~~虽然现在没实现我的dre ...

  10. Java常用设计模式————建造者模式

    引言 建造者模式(Builder Pattern)使用多个简单对象一步一步构建成一个复杂的对象.这种类型的设计模式属于建造型模式,它提供了一种创建对象的最佳方式. 一个Builder会一步步构建最终的 ...

最新文章

  1. hurst代码 python_python数据类型—字符串
  2. scala成长之路(2)对象和类
  3. 中文NER任务实验小结:BERT-MRC的再优化
  4. 对称振子天线matlab程序,对称振子天线详解.ppt
  5. JAVA两个视图层_MVC - 管理帐户 . 一个视图有两个局部视图和两个模型
  6. 编译速度谁“最快”?25岁的 C++Builder 还能打
  7. 现在论文用手写还是用计算机写,毕业论文计算机手写数字识别技术完整版.docx...
  8. 将查询出来的数据按照一个字段分组且排序过程中,遇到的一些有关group的问题(分组排序应该使用partition by)
  9. Destroy与DestroyImmediate以及引发的bug
  10. 维护LINQ to SQL多对多表间关系[转]
  11. 手机辅助java脚本_android 手机一个辅助阅读工具
  12. linux免杀工具,安卓Apk免杀工具:backdoor-apk 教程
  13. python numpy 中linspace函数
  14. python调用WinRAR暴力获取压缩密码 用网址做解压密码
  15. 艺龙的执着与固执:等待微信
  16. Linux查看文件数量
  17. AOP底层实现原理、基于注解的AOP编程、AOP开发中的一个坑 打卡第八天
  18. 和导师闹僵跑来实习?拼了命也要拿到大厂实习offer
  19. OpenWrt之DNS域名解析系统(/etc/resolv.conf)
  20. conda 查看现有虚拟环境 - 删除现有虚拟环境

热门文章

  1. 【NLP】第 1 章 : 语言模型简介
  2. 奥德赛海洋勘探公司(NASDAQ:OMEX)诉墨西哥案中的重要仲裁事项需要股东提供意见
  3. 简单的特效--css画圆圈
  4. 怎么把visio 2010中的框中的字变成竖排以及如何将visio图插入word
  5. Druid学习笔记(一) - 监控功能的开启
  6. 温度对服务器运行耗电影响,真相大白 温度对耗电影响几何
  7. Nginx - 盗链与防盗链重定向
  8. python文字转为图片
  9. 【C++基础】删除vector中指定下标元素
  10. 答研一学生:你的奋斗在哪里?