C++Builder建造者模式详解--设计模式(4)
生活中有着很多的builder的例子,个人觉得大学生活就是一个builder模式的最好体验:要完成大学教育,一般将大学教育过程分成4个学期进行,因此没有学习可以看作是构建完整大学教育的一个部分构建过程,每个人经过这4年的(4个阶段)构建过程得到的最后的结果不一样,因为可能在四个阶段的构建中引入了很多的参数(每个人的机会和际遇不完全相同)。
builder模式要解决的也正是这样的问题:当我们要创建的对象很复杂的时候(通常是由很多其他的对象组合而成),我们要要复杂对象的创建过程和这个对象的表示(展示)分离开来,这样做的好处就是通过一步步的进行复杂对象的构建,由于在每一步的构造过程中可以引入参数,使得经过相同的步骤创建最后得到的对象的展示不一样。
builder模式的uml结构图如图1所示:
builder模式的关键是其中的director对象并不直接返回对象,而是通过一步步(buildparta,buildpartb,buildpartc)来一步步进行对象的创建。当然这里director可以提供一个默认的返回对象的接口(即返回通用的复杂对象的创建,即不指定或者特定唯一指定buildpart中的参数)。
builder模式的实现基于以下几个面向对象的设计原则:
1)把变化的部分提取出来形成一个基类和对应的接口函数,在这里不会变化的是都会创建parta和partb,变化的则是不同的创建方法,于是就抽取出这里的builder基类和buildparta,buildpartb接口函数
2)采用聚合的方式聚合了会发生变化的基类,就是这里director聚合了builder类的指针.
以上,通过两个派生类concretebuilder1、concretebuilder2定义了两种不同的建造细节(建造步骤是一样的,由construct函数确定),通过两个派生类所建造出来的对象,对外部所展现出来的属性或者功能是不一样的,由各自builder派生类中的建造方法(buildparta、buildpartb、buildpartc)决定。
builder.h
#ifndef _builder_h_ #define _builder_h_ #include #include using namespace std; //产品类 class product { private: string m_parta; string m_partb; string m_partc; public: void setparta(const string& s); void setpartb(const string& s); void setpartc(const string& s); product(); ~product(); }; //抽象builder基类,定义不同部分的创建接口 class builder { public: virtual void buildparta()=0; virtual void buildpartb()=0; virtual void buildpartc()=0; virtual product* getproduct()=0; builder(); virtual ~builder(); }; // builder的派生类,实现builderparta和builderpartb和buildpartc接口函数 class concretebuilder1:public builder { public: concretebuilder1(); ~concretebuilder1(); virtual void buildparta(); virtual void buildpartb(); virtual void buildpartc(); virtual product* getproduct(); private: product* m_pproduct; }; // builder的派生类,实现builderparta和builderpartb和buildpartc接口函数 class concretebuilder2:public builder { public: concretebuilder2(); ~concretebuilder2(); virtual void buildparta(); virtual void buildpartb(); virtual void buildpartc(); virtual product* getproduct(); private: product* m_pproduct; }; //concretebuilder1与concretebuilder2是builder的两个派生类,用于实现两种不同的建造细节 // 使用builder构建产品,构建产品的过程都一致,但是不同的builder有不同的实现 // 这个不同的实现通过不同的builder派生类来实现,存有一个builder的指针,通过这个来实现多态调用 class director { public: director(builder* pbuilder); ~director(); //construct函数定义一个对象的整个构建过程,不同的部分之间的装配方式都是一致的, //首先构建parta其次是partb,只是根据不同的构建者会有不同的表示 void construct(); //void construct(const string& buildpara); private: builder* m_pbuilder; }; #endif
director.cpp
#include "builder.h" #include #include using namespace std; product::~product() { } product::product() {} void product::setparta(const string& s) { this->m_parta = s; } void product::setpartb(const string& s) { this->m_partb = s; } void product::setpartc(const string& s) { this->m_partc = s; } builder::builder() {} builder::~builder() {} concretebuilder1::concretebuilder1() { this->m_pproduct = new product(); cout<<"create empty product!"<m_pproduct->setparta("a"); cout<<"buildparta"<m_pproduct->setpartb("b"); cout<<"buildpartb"<m_pproduct->setpartc("c"); cout<<"buildpartc"<m_pproduct; } concretebuilder1::~concretebuilder1() { delete this->m_pproduct; this->m_pproduct = null; } concretebuilder2::concretebuilder2() { this->m_pproduct = new product(); cout<<"create empty product!"<m_pproduct->setparta("a"); cout<<"buildparta"<m_pproduct->setpartb("b"); cout<<"buildpartb"<m_pproduct->setpartc("c"); cout<<"buildpartc"<m_pproduct; } concretebuilder2::~concretebuilder2() { delete this->m_pproduct; this->m_pproduct = null; } director::director(builder* pbuilder) { this->m_pbuilder = pbuilder; } void director::construct() { this->m_pbuilder->buildparta(); this->m_pbuilder->buildpartb(); this->m_pbuilder->buildpartc(); } director::~director() { delete this->m_pbuilder; this->m_pbuilder = null; }
#include "builder.h" #include using namespace std; int main() { director* pdirector = new director(new concretebuilder1()); pdirector->construct(); director* pdirector1 = new director(new concretebuilder2()); pdirector1->construct(); return 0; }
建造者模式和工厂模式使用很相似,但也有区别:
建造者模式最主要功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了;而工厂方法则重点是创建,你要什么对象我创造一个对象出来,组装顺序则不是他关心的。
建造者模式使用的场景,一是产品类非常的复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式是非常合适。
下一篇: node.js