设计模式(五)——建造者模式

一、建造者模式简介

1、建造者模式简介

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

    建造者模式和抽象工厂模式在功能上很相似,都是用来创建大的复杂的对象,区别是:建造者模式强调的是一步步创建对象,并通过相同的创建过程可以获得不同的结果对象,一般来说建造者模式中对象不是直接返回的。而在抽象工厂模式中对象是直接返回的,抽象工厂模式强调的是为创建多个相互依赖的对象提供一个同一的接口。

    建造者模式最主要功能是基本方法的调用顺序安排,即对象的组装顺序,而工厂方法则重点是创建,要什么对象创造一个对象出来,组装顺序则不是他关心的。

    建造者模式的特点如下:

         A建造者模式是将一个复杂对象的创建过程给封装起来,客户只需要知道可以利用对象名或者类型就能够得到一个完整的对象实例,而不需要关心对象的具体创建过程。

    B建造者模式将对象的创建过程与对象本身隔离开了,使得细节依赖于抽象,符合依赖倒置原则。可以使用相同的创建过程来创建不同的产品对象。

wKiom1nQmSrTfMLIAAD3QkHwgjU541.jpg

2、建造者模式角色

指挥者Director:构建一个使用Builder对象的接口,Construct函数通过调用具体建造者的接口函数完成对象的构建各个不同部分装配的过程都是一致的但不同的构建方式会有不同的表示(根据Builder的实际类型来决定如何构建也就是多态)。指挥者角色的作用是隔离了客户与对象的生产过程负责控制产品对象的生产过程。指挥者负责调用适当的建造者来组建产品,一般不与产品类发生依赖关系,与指挥者类直接交互的是建造者类。一般来说,指挥者列被用来封装程序中易变的部分。

建造者Builder:定义创建对象过程的抽象,提供构建不同组成部分的接口buildPartAbuildPartBbuildPartC是对一个对象不同部分的构建函数接口Builder的派生类ConcreteBuilderMConcreteBuilderN来具体实现组建产品;返回组建好的产品。

产品类Product:一般是一个较为复杂的对象,创建对象的过程比较复杂,一般会有比较多的代码量。实际编程中,产品类可以是由一个抽象类及其不同实现组成,也可以是由多个抽象类及其实现组成。

一个对象可能有不同的组成部分,不同部分的创建在创建对象会有不同的表示但各个部分之间装配的方式是一致的。例如一辆单车由车轮车座等等的构成的(一个对象不同的组成部分)不同的品牌生产出来的不一样(不同的构建方式)虽然不同的品牌构建出来的单车不同但构建的过程还是一样的Director::Construct函数中固定了各个组成部分的装配方式,当具体是装配怎样的组成部分由Builder的派生类实现

    Builder模式的实现基于几个面向对象的设计原则:

    A把变化的部分提取出来形成一个基类和对应的接口函数不会变化的是都会创建PartAPartB变化的则是不同的创建方法于是就抽取出Builder基类和BuildPartA,BuildPartB接口函数

    B采用聚合的方式聚合了会发生变化的基类就是Director聚合了Builder类的指针

    通过两个派生类ConcreteBuilderMConcreteBuilderN定义了两种不同的建造细节(建造步骤是一样的,由Construct函数确定),通过两个派生类所建造出来的对象,对外部所展现出来的属性或者功能是不一样的,由各自Builder派生类中的建造方法(BuildPartABuildPartBBuildPartC)决定。

3、建造者模式优缺点

    优点:

    A建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。

 B建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。

 C将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,使得我们能够更加精确的控制复杂对象的产生过程。

 D将产品的创建过程与产品本身分离开来,可以使用相同的创建过程来得到不同的产品。

 E每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。

缺点:

        A、要求构建产品的步骤(算法)是不能剧烈变化的,最好是不变的,影响了灵活度。

    B如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现内部复杂的变化,导致系统变得很庞大。

4、建造者模式使用场景

    建造者模式使用场景:

 A建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
B当创建复杂对象的算法应该独立于对象的组成部分以及装配方式时。

 C当构造过程必须允许被构造的对象各部分有不同的表示时。

 D需要生成的产品对象有复杂的内部结构,产品对象通常包含多个成员属性。

二、建造者模式实现

    Builder模式的实现基于以下几个面向对象的设计原则:

    A把变化的部分提取出来形成一个基类和对应的接口函数不会变化的是都会创建PartAPartBPartC变化的是不同的创建方法于是就抽取出Builder基类和buildPartAbuildPartBbuildPartC接口函数

    B采用聚合的方式聚合了会发生变化的基类,即Director聚合了Builder类的指针

    通过两个派生类ConcreteBuilderMConcreteBuilderN定义了两种不同的建造细节(建造步骤是一样的,由Construct函数确定),通过两个派生类所建造出来的对象,对外部所展现出来的属性或者功能是不一样的,由各自Builder派生类中的建造方法(BuildPartABuildPartBBuildPartC)决定。

Product.h文件:
#ifndef PRODUCT_H
#define PRODUCT_H
#include <string>
#include <iostream>
using namespace std;
 
class Product
{
public:
    Product();
    ~Product();
    void setPartA(const string& s);
    void setPartB(const string& s);
    void setPartC(const string& s);
private:
    string m_PartA;
    string m_PartB;
    string m_PartC;
};
 
#endif // PRODUCT_H
Product.cpp文件:
#include "Product.h"
 
Product::Product()
{
}
 
Product::~Product()
{
 
}
 
void Product::setPartA(const string& s)
{
    m_PartA = s;
}
 
void Product::setPartB(const string& s)
{
    m_PartB = s;
}
 
void Product::setPartC(const string& s)
{
    m_PartC = s;
}
Director.h文件:
//使用Builder构建产品,构建产品的过程都一致,但是不同的builder有不同的实现
// 不同的实现通过不同的Builder派生类来实现,存有一个Builder的指针,通过这个来实现多态调用
 
#ifndef DIRECTOR_H
#define DIRECTOR_H
#include "Builder.h"
 
class Director
{
public:
    Director(Builder* pBuilder);
    ~Director();
 //Construct函数定义一个对象的整个构建过程,不同的部分之间的装配方式都是一 //致的,首先构建PartA其次是PartB,只是根据不同的构建者会有不同的表示 
    void construct();
private:
    Builder* m_pBuilder;
};
 
#endif // DIRECTOR_H
 
Director.cpp文件:
#include "Director.h"
 
Director::Director(Builder* pBuilder)
{
    m_pBuilder = pBuilder;
}
 
Director::~Director()
{
 
}
 
void Director::construct()
{
    m_pBuilder->buildPartA();
    m_pBuilder->buildPartB();
    m_pBuilder->buildPartC();
 
}
Builder.h文件:
//抽象Builder基类,定义不同部分的创建接口
#ifndef BUILDER_H
#define BUILDER_H
#include "Product.h"
 
class Builder
{
public:
    Builder();
    virtual ~Builder();
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product* getProduct() = 0;
};
 
#endif // BUILDER_H
Builder.cpp文件:
#include "Builder.h"
 
Builder::Builder()
{
}
 
Builder::~Builder()
{
}
ConcreteBuilderM.h文件:
//Builder的派生类,实现BuilderPartA和BuilderPartB和BuildPartC接口函数
#ifndef CONCRETEBUILDERM_H
#define CONCRETEBUILDERM_H
#include "Builder.h"
 
class ConcreteBuilderM : public Builder
{
public:
    ConcreteBuilderM();
    ~ConcreteBuilderM();
    virtual void buildPartA();
    virtual void buildPartB();
    virtual void buildPartC();
    virtual Product* getProduct();
private:
    Product* m_pProduct;
};
 
#endif // CONCRETEBUILDERM_H
 
ConcreteBuilderM.cpp文件:
#include "ConcreteBuilderM.h"
 
ConcreteBuilderM::ConcreteBuilderM()
{
    m_pProduct = new Product();
    cout << "ConcreteBuilderM" << endl;
}
 
ConcreteBuilderM::~ConcreteBuilderM()
{
    delete m_pProduct;
    m_pProduct = NULL;
}
 
void ConcreteBuilderM::buildPartA()
{
    m_pProduct->setPartA("A");
    cout << "ConcreteBuilderM::buildPartA()"<< endl;
 
}
 
void ConcreteBuilderM::buildPartB()
{
    m_pProduct->setPartB("B");
    cout << "ConcreteBuilderM::buildPartB()"<< endl;
 
}
 
void ConcreteBuilderM::buildPartC()
{
    m_pProduct->setPartC("C");
    cout << "ConcreteBuilderM::buildPartC()"<< endl;
 
}
 
Product* ConcreteBuilderM::getProduct()
{
    return m_pProduct;
 
}
ConcreteBuilderN.h文件:
//Builder的派生类,实现BuilderPartA和BuilderPartB和BuildPartC接口函数 
#ifndef CONCRETEBUILDERN_H
#define CONCRETEBUILDERN_H
#include "Builder.h"
 
class ConcreteBuilderN : public Builder
{
public:
    ConcreteBuilderN();
    ~ConcreteBuilderN();
    virtual void buildPartA();
    virtual void buildPartB();
    virtual void buildPartC();
    virtual Product* getProduct();
private:
    Product* m_pProduct;
};
 
#endif // CONCRETEBUILDERN_H
 
ConcreteBuilderN.cpp文件:
#include "ConcreteBuilderN.h"
 
ConcreteBuilderN::ConcreteBuilderN()
{
    m_pProduct = new Product();
    cout << "ConcreteBuilderN" << endl;
}
 
ConcreteBuilderN::~ConcreteBuilderN()
{
    delete m_pProduct;
    m_pProduct = NULL;
}
 
void ConcreteBuilderN::buildPartA()
{
    m_pProduct->setPartA("A");
    cout << "ConcreteBuilderN::buildPartA()"<< endl;
 
}
 
void ConcreteBuilderN::buildPartB()
{
    m_pProduct->setPartB("B");
    cout << "ConcreteBuilderN::buildPartB()"<< endl;
 
}
 
void ConcreteBuilderN::buildPartC()
{
    m_pProduct->setPartC("C");
    cout << "ConcreteBuilderN::buildPartC()"<< endl;
 
}
 
Product* ConcreteBuilderN::getProduct()
{
    return m_pProduct;
 
}
Main.cpp文件:
#include <iostream>
#include "Director.h"
#include "ConcreteBuilderM.h"
#include "ConcreteBuilderN.h"
 
using namespace std;
 
int main()
{
    Director* director1 = new Director(new ConcreteBuilderM());
    director1->construct();
 
    Director* director2 = new Director(new ConcreteBuilderN());
    director2->construct();
 
    delete director1;
    delete director2;
    return 0;
}