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

 更新时间:2016年03月08日 09:34:18   作者:曾经的你|  
这篇文章主要介绍了C++设计模式编程中建造者模式的实现,建造者模式将一个复杂对象的构建于它的表现分离,可以减少代码冗余,需要的朋友可以参考下

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

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

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

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

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

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

20163892712891.jpg (794×468)

图中可以看到,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; 
} 

20163892815043.png (675×418)

相关文章

  • C++插件化 NDD源码的插件机制实现解析

    C++插件化 NDD源码的插件机制实现解析

    这篇文章主要介绍了C++插件化 NDD源码的插件机制实现解析,这里再介绍推荐下优秀的国产软件开源项目 NDD(notepad--),一个支持windows/linux/mac的文本编辑器,目标是要国产替换同类软件,需要的朋友可以参考下
    2023-03-03
  • C语言如何建立链表并实现增删查改详解

    C语言如何建立链表并实现增删查改详解

    这篇文章主要给大家介绍了关于C语言如何建立链表并实现增删查改的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C语言具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • C语言解读数组循环右移问题

    C语言解读数组循环右移问题

    这篇文章主要介绍了C语言解读数组循环右移问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C语言由浅入深讲解文件的操作上篇

    C语言由浅入深讲解文件的操作上篇

    C语言具有操作文件的能力,比如打开文件、读取和追加数据、插入和删除数据、关闭文件、删除文件等。与其他编程语言相比,C语言文件操作的接口相当简单和易学
    2022-04-04
  • c语言中的二级指针做函数参数说明

    c语言中的二级指针做函数参数说明

    这篇文章主要介绍了c语言中的二级指针做函数参数说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • 简单了解设计模式中的装饰者模式及C++版代码实现

    简单了解设计模式中的装饰者模式及C++版代码实现

    这篇文章主要介绍了简单了解设计模式中的装饰者模式及C++版代码实现,ConcreteComponent的引用(指针)也可以达到修饰的功能,需要的朋友可以参考下
    2016-03-03
  • C++人工模拟栈实现方法

    C++人工模拟栈实现方法

    在本篇内容里小编为大家整理了关于C++人工模拟栈实现方法和步骤,需要的朋友们可以学习下。
    2018-12-12
  • C语言内存操作函数使用示例梳理讲解

    C语言内存操作函数使用示例梳理讲解

    这篇文章主要介绍了C语言库函数中的内存操作函数memcpy()、memmove()、memset()、memcmp()使用示例分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-09-09
  • 关于AVLTree(C++实现)没有统一旋转操作的问题

    关于AVLTree(C++实现)没有统一旋转操作的问题

    这篇文章主要介绍了关于AVLTree(C++实现)没有统一旋转操作的问题,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • FFmpeg进阶教程之给视频添加文字水印

    FFmpeg进阶教程之给视频添加文字水印

    FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序,下面这篇文章主要给大家介绍了关于FFmpeg进阶教程之给视频添加文字水印的相关资料,需要的朋友可以参考下
    2022-11-11

最新评论