详解C++设计模式编程中建造者模式的实现

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。这是建造者模式的标准表达,不过看着让人迷惑,什么叫构建和表示的分离?一个对象使用构造函数构造之后不就固定了,只有通过它方法来改变它的属性吗?而且还要同样的构建过程搞出不同的表示,怎么可能呢?多写几个构造函数?

其实多写几个构造函数,根据不同参数设置对象不同的属性,也可以达到这样的效果,只是这样就非常麻烦了,每次要增加一种表示就要添加一个构造函数,将来构造函数会多得连自己都不记得了,这违背了开放-封闭的原则。

要不就只能设计几个set函数,每次属性不一样了,我就构造一个对象,然后用set函数改变对象的属性。这样也可以达到效果。只是代码就会非常冗余了,每个要用到这个对象的地方,都要写上好几句语句,一旦对象有点什么变化,还得到处都改一遍,这样就很容易出错,以后别人看着这种神逻辑和神代码估计也会崩溃了。而且这也违背了依赖倒转的原则。

于是大神们就开始想了,不能加很多构造函数,也不能直接用一堆set函数,然后发现,有些对象的构建是固定的几个步骤的,就像一条流水线一样,任何的产品都是通过每一个固定的步骤拼凑出来的。例如说一部手机,先放主板,再放屏幕,再放电池,再放外壳,贴个膜就能卖几千了,每次推出新产品,就换个更好的主板,换个大点的屏幕,再整个大容量电池,贴个超牛B的高透膜,又能卖出个新价钱。就是说,这些步骤都没有变,变的只是每个部分的东西。

这就是大神的厉害之处了,透过现象看本质,基本有变的,有不变的,那敢情好,面向对象的一个重要指导思想就是,封装隔离变化的,留出不变的。于是他们就用一个Builder类把步骤中的每个部分封装起来,这个类的主要作用就是生产每个部件,再抽象一下提升高度,这样就依赖倒转了,这样每次只需要添加一个类,这个类还是这几个部分,只是内部的实现已经不一样了,这样就满足了开放-封闭的原则了。但还是有一个问题,光有Builder类还不行,虽然产品的每个部分都有对应的函数,但是用起来的话,还是跟前面说的set函数一样,一用就要使用一大堆函数,也就是这变的东西是封装起来了,但这不变的东西还没留出来。这时,就添加一个Director类,这个类就是专门规定组装产品的步骤的,这样只要告诉Director使用哪个Builder,就能生产出不同的产品,对于客户端来说,只看到用了Director的一个construct函数,甚是方便。

再反过来看建造者模式的定义,构建指的就是生产一个产品的步骤,表示就是每个产品部分的具体实现,通过Director封装步骤,通过Builder封装产品部分的实现,再把他两隔离开,就能隔离变的,留出不变的供客户端使用。

图中可以看到,Product是必须要知道,没有抽象,但是这个产品却可以由不同的部分组合而成。Director里的construct也是固定,没有抽象出来,如果要更改步骤,也要添加一个函数,或者再添一个Diector,所以建造者模式一般应用于步骤不会发生大的变化,而产品会发生大变化的情况。

常用的场景
C#中的StringBuilder就是一个建造者的例子,但只是一个建造者,还缺一个Director,不能算一个完整的建造者模式。建造者模式一般应用于构建产品的步骤(也可以称为算法)不变,而每个步骤的具体实现又剧烈变化的情况。

优点
1.隔离了构建的步骤和具体的实现,为产品的具体实现提供了灵活度。

2.封装和抽象了每个步骤的实现,实现了依赖倒转原则。

3.封装了具体的步骤,减少了代码的冗余。

缺点
1.要求构建产品的步骤(算法)是不能剧烈变化的,最好是不变的,这样就影响了灵活度。

实例

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
using namespace std; 

//抽象类,用来安排创建人的具体流程,其他类必须遵循这个流程,但是可以自己具体实现
class CPersonBuilder
{
public:
 virtual void BuildHead()=0;
 virtual void BuildBody()=0;
 virtual void BuildArmLeft()=0;
 virtual void BuildArmRight()=0;
 virtual void BuildLegLeft()=0;
 virtual void BuildLegRight()=0;
}; 

//创建瘦子的类
class CThinPersonBuilder:public CPersonBuilder
{
public:
 CThinPersonBuilder()
 {
 cout<<"is creating thin person "<<endl<<endl;
 }
 ~CThinPersonBuilder()
 {
 cout<<"is finished for thin person"<<endl<<endl;
 }
public:
 void BuildHead()
 {
 cout<<"BuildHead"<<endl;
 }
 void BuildBody()
 {
 cout<<"BuildBody(thin)"<<endl;
 }
 void BuildArmLeft()
 {
 cout<<"BuildArmLeft"<<endl;
 }
 void BuildArmRight()
 {
 cout<<"BuildArmRight"<<endl;
 }
 void BuildLegLeft()
 {
 cout<<"BuildLegLeft"<<endl;
 }
 void BuildLegRight()
 {
 cout<<"BuildLegRight"<<endl;
 }
};
 //创建胖子的类
class CFatPersonBuilder:public CPersonBuilder
{
public:
 CFatPersonBuilder()
 {
 cout<<"is creating fat person"<<endl;
 }
 ~CFatPersonBuilder()
 {
 cout<<"is finished for fat person"<<endl;
 }
public:
 void BuildHead()
 {
 cout<<"BuildHead"<<endl;
 }
 void BuildBody()
 {
 cout<<"BuildBody(Fat)"<<endl;
 }
 void BuildArmLeft()
 {
 cout<<"BuildArmLeft"<<endl;
 }
 void BuildArmRight()
 {
 cout<<"BuildArmRight"<<endl;
 }
 void BuildLegLeft()
 {
 cout<<"BuildLegLeft"<<endl;
 }
 void BuildLegRight()
 {
 cout<<"BuildLegRight"<<endl;
 }
}; 

//指挥者类,用来指挥创建的人是瘦子还是胖子
class CPersonDirector
{
public:
 CPersonDirector(CPersonBuilder *p)
 {
 this->m_p=p;
 }
 const void CreatePerson(void) const
 {
 m_p->BuildHead();
 m_p->BuildBody();
 m_p->BuildArmLeft();
 m_p->BuildArmRight();
 m_p->BuildLegLeft();
 m_p->BuildLegRight();
 }
private:
 CPersonBuilder *m_p;
}; 

int _tmain(int argc, _TCHAR* argv[])
{
 cout<<"---------建造者模式测试案例------------------------"<<endl<<endl; 

 CThinPersonBuilder *p_tp=new CThinPersonBuilder();
 CPersonDirector *p_dtp=new CPersonDirector(p_tp);
 p_dtp->CreatePerson();
 delete p_tp;
 delete p_dtp;
 p_tp=NULL;
 p_dtp=NULL;
 cout<<endl<<endl; 

 CFatPersonBuilder *p_fp=new CFatPersonBuilder();
 CPersonDirector *p_dfp=new CPersonDirector(p_fp);
 p_dfp->CreatePerson();
 delete p_fp;
 delete p_dfp;
 p_fp=NULL;
 p_dfp=NULL;
 system("pause");
 return 0;
}

(0)

相关推荐

  • C++设计模式之建造者模式

    建造者模式 在GOF的<设计模式 可复用面向对象软件的基础>中是这样说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 这句话,似懂非懂的.一个复杂对象的创建,其通常是由很多的子对象构成:如果一个对象能够直接就创建好了,那么也不会称之为复杂对象.由于项目中需求的变化,这个复杂对象的各个部分经常会发生剧烈的变化,但是,不管怎么变化,将它们组合在一起,组成一个复杂的对象的事实是不会变的.建造者模式就提供了一种"封装机制"来将各个对象的变化隔离开,最

  • 全面解析设计模式中的建造者模式及相关C++实现

    生活中有着很多的建造者的例子,个人觉得大学生活就是一个建造者模式的最好体验: 要完成大学教育,一般将大学教育过程分成 4 个学期进行,因此没有学习可以看作是构建完整大学教育的一个部分构建过程,每个人经过这 4 年的(4 个阶段)构建过程得到的最后的结果不一样,因为可能在四个阶段的构建中引入了很多的参数(每个人的机会和际遇不完全相同). 建造者模式要解决的也正是这样的问题:当我们要创建的对象很复杂的时候(通常是由很多其他的对象组合而成),我们要要复杂对象的创建过程和这个对象的表示(展示)分离开来,

  • 详解C++设计模式编程中建造者模式的实现

    建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.这是建造者模式的标准表达,不过看着让人迷惑,什么叫构建和表示的分离?一个对象使用构造函数构造之后不就固定了,只有通过它方法来改变它的属性吗?而且还要同样的构建过程搞出不同的表示,怎么可能呢?多写几个构造函数? 其实多写几个构造函数,根据不同参数设置对象不同的属性,也可以达到这样的效果,只是这样就非常麻烦了,每次要增加一种表示就要添加一个构造函数,将来构造函数会多得连自己都不记得了,这违背了开放-封闭的原则. 要

  • 详解C#设计模式编程中生成器模式的使用

    一.概述 在软件系统中,有时候面临着复杂的对象创建,该对象由一定算法构成的子对象组成,由于需求变化,这些子对象会经常变换,但组合在一起的算法却是稳定的.生成器模式可以处理这类对象的构建,它提供了一种封装机制来隔离各类子对象的变化,从而保证系统的稳定. 二.生成器模式 生成器模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.其结构图如下: Builder为创建Product对象的各个子对象指定抽象接口. ConcreteBuilder实现了Builder接口,用于创建P

  • 详解Java设计模式编程中命令模式的项目结构实现

    正论: 命令模式把一个请求或者操作封装到一个对象中.命令模式运行系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 通俗: 其实很好理解.命令模式,关心的就是命令(或者称为操作).打个比方.在一个公司里面,整个运作就像一个系统.某个boss发布了一个命令,中层领导接到这个命令,然后指派给具体负责这个员工.整个流程很清晰吧.有一个需求,如何将这个流程固定下来,形成一个系统.我们只要抓住了重点:命令.将它抽取出来,其他的都迎刃而解了.抽取出命令,封装成一个独

  • 详解C++设计模式编程中策略模式的优缺点及实现

    策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法的变化不会影响到使用算法的客户.策略模式和 Template 模式要解决的问题是相同(类似)的,都是为了给业务逻辑(算法)具体实现和抽象接口之间的解耦.策略模式将逻辑(算法)封装到一个类(Context)里面,通过组合的方式将具体算法的实现在组合对象中实现,再通过委托的方式将抽象接口的实现委托给组合对象实现.State 模式也有类似的功能,他们之间的区别将在讨论中给出. UML图

  • 详解Java设计模式编程中的策略模式

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换. 类型:行为类模式 类图: 策略模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换.在前面说过的行为类模式中,有一种模式也是关注对算法的封装--模版方法模式,对照类图可以看到,策略模式与模版方法模式的区别仅仅是多了一个单独的封装类Context,它与模版方法模式的区别在于:在模版方法模式中,调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是封装到了封装类Context中

  • 深入解析Java的设计模式编程中建造者模式的运用

    定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 类型:创建类模式 类图: 四个要素 产品类:一般是一个较为复杂的对象,也就是说创建对象的过程比较复杂,一般会有比较多的代码量.在本类图中,产品类是一个具体的类,而非抽象类.实际编程中,产品类可以是由一个抽象类与它的不同实现组成,也可以是由多个抽象类与他们的实现组成. 抽象建造者:引入抽象建造者的目的,是为了将建造的具体过程交与它的子类来实现.这样更容易扩展.一般至少会有两个抽象方法,一个用来建造产品,一个是用来返回

  • 深入解析Python设计模式编程中建造者模式的使用

    建造者模式:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示. 基本思想 某类产品的构建由很多复杂组件组成: 这些组件中的某些细节不同,构建出的产品表象会略有不同: 通过一个指挥者按照产品的创建步骤来一步步执行产品的创建: 当需要创建不同的产品时,只需要派生一个具体的建造者,重写相应的组件构建方法即可. 代码结构 class Builder(object): """基类""" def Part1(self): # 不同类型

  • 详解Java设计模式编程中的访问者模式

    定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作. 类型:行为类模式 类图: 例子: 例如,思考一下添加不同类型商品的购物车,当点击结算的时候,它计算出所有不同商品需付的费用.现在,计算逻辑即为计算这些不同类型商品的价格.或者说通过访问者模式我们把此逻辑转移到了另外一个类上面.让我们实现这个访问者模式的例子. 为了实现访问者模式,最先需要做的是创建能够被添加到购物车中代表不同类型商品(itemElement)的类. ItemElement

  • 详解Java设计模式编程中的Flyweight享元模式的开发结构

    享元(Flyweight)模式:通过共享技术以便有效的支持大量细粒度的对象. 享元模式在阎宏的<java与模式>中分为单纯享元模式和复合享元模式,复合模式的复合享元是不可以共享的,享元对象能做到共享的关键是区分内蕴态(Internal State)和外蕴态( External State).这两个"蕴态"翻译的太难懂,我不是说翻译的不好,可能是我理解能力差,还是<Design Pattern Elements of Reusable Object-Oriented S

  • 详解C#设计模式编程中的模板方法模式使用

    一.引言 提到模板,大家肯定不免想到生活中的"简历模板"."论文模板"."Word中模版文件"等,在现实生活中,模板的概念就是--有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下载下来的简历模板的格式都是相同的,然而我们下载下来简历模板之后我们可以根据自己的情况填充不同的内容要完成属于自己的简历.在设计模式中,模板方法模式中模板和生活中模板概念非常类似,下面让我们就详细介绍模板方法的定义,大家可以根据生活中模板的概

随机推荐