天天看點

生成器模式(建造者模式 Builder)

設計模式系列

Builder(生成器)——對象建立模式

1.意圖

将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。

2.适用性

  • 當建立複雜對象的算法應該獨立于該對象的組成部分以及它們的裝配方式時。
  • 當建立過程必須允許被構造的對象有不同的表示時。

3.結構

生成器模式(建造者模式 Builder)

4.參與者

  • Builder

—— 為建立一個Product對象的各個部件指定抽象接口

  • ConcreteBuilder

—— 實作Builder的接口以構造和裝配該産品的各個部件

—— 定義并明确它所建立的表示

—— 提供一個檢索産品的接口

  • Director

—— 構造一個可以使用Builder接口的對象

  • Product

—— 表示被構造的複雜對象。ConcreteBuilder建立該産品的内部表示并定義它的裝配過程

—— 包含定義組成部件的類,包含将這些部件裝配成最終産品的接口

5.協作

  • 客戶建立Director對象,并用它所想要的Builder對象進行配置
  • 一旦産品部件被生成,導向器就會通知生成器
  • 生成器處理導向器的請求,并将部件添加到該産品中
  • 客戶從生成器中檢索産品

下面的互動圖說明了Builder和Director是如何與一個客戶協作的

生成器模式(建造者模式 Builder)

6.效果

  1. 它使你可以改變一個産品的内部表示
  2. 它将構造代碼和表示代碼分開
  3. 它使你可對構造過程進行更精細的控制

7.優缺點

優點:

  1. 生成器模式最核心的就是分離其構造過程群組成部分,實作兩者的松耦合
  2. 細節隐藏,産品的組成部分的建構和産品的建構分别由 Builder 和 Director 來負責,使用者隻需要使用兩者就可以生成最終的産品
  3. 更好的複用,産品的建構流程可以複用,組成部分也可以複用。

缺點:

  1. 更複雜,了解難度更高
  2. 類增多

8.相關模式

Abstract Factory與Builder相似,因為它也可以建立複雜對象。主要的差別是Builder模式着重于一步步構造一個複雜對象。而Abstract Factory着重于多個系列的産品對象(簡單的或是複雜的), Builder在最後的一步傳回産品,而對于Abstract Factory來說,産品是立即傳回的。

Composite (4.3)通常是用Builder生成的。

9.案例實作

以銀行賬單為例,賬單由擡頭、賬單内容(多條資料)、結尾,三個部分組成。賬單組成部分是固定的(擡頭、交易記錄、結尾)三大部分組成,但賬單的格式可以用多種可以用txt格式、也可以用xml格式。

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template<class T>
string ConvertToString(T value) 
{
    stringstream ss;
    ss << value;
    return ss.str();
}

class ExportHeaderModel 
{
public:
    ExportHeaderModel(string strDepId, string strExportDate) : m_strDepId(strDepId), m_strExportDate(strExportDate) {}
    string getDepId() { return m_strDepId; }
    string getExportDate() { return m_strExportDate; }

private:
    string m_strDepId;//對賬單的部門id
    string m_strExportDate;//對賬單的導出日期
};

class ExportDataModel 
{
public:
    ExportDataModel(string strTransId, double Quantity) : m_strTransId(strTransId), m_Quantity(Quantity) { }
    string getTransId() { return m_strTransId; }
    double getQuantity() { return m_Quantity; }
private:
    string m_strTransId;//交易Id
    double m_Quantity;
};

class ExportFooterModel 
{
public:
    ExportFooterModel(string exportUser) : m_exportUser(exportUser) {}
    string getExportUser() { return m_exportUser; }
private:
    string m_exportUser;
};

class Builder 
{
public:
    virtual void builderHeader(ExportHeaderModel& ehm) = 0;
    virtual void builderBody(vector < ExportDataModel*>& edmCollection) = 0;
    virtual void builderFoot(ExportFooterModel& efm) = 0;
    virtual string getResult() = 0;
protected:
    Builder() {}
};

class TxtBuilder : public Builder 
{
public:
    void builderHeader(ExportHeaderModel& ehm) { m_strResulst.append(ehm.getDepId() + "," + ehm.getExportDate() + "\n"); }
    void builderBody(vector < ExportDataModel*> & edmCollection) 
    {
        for (vector<ExportDataModel*>::iterator iter = edmCollection.begin(); iter != edmCollection.end(); iter++)
        {
            m_strResulst += (*iter)->getTransId() + ":" + ConvertToString((*iter)->getQuantity()) + "\n";
        }
    }
    void builderFoot(ExportFooterModel & efm) { m_strResulst += efm.getExportUser() + "\n"; }
    string getResult() { return m_strResulst; }

public:
    TxtBuilder() { m_strResulst = ""; }
private:
    string m_strResulst;
};

class XmlBuilder : public Builder 
{
public:
    void builderHeader(ExportHeaderModel& ehm) 
    {
        m_strResulst.append("<?xml version='1.0' encoding='utf-8'>\n");
        m_strResulst.append("<Receipt>\n");
        m_strResulst.append("    <Header>\n");
        m_strResulst.append("        <DepId>");
        m_strResulst.append(ehm.getDepId() + "</DepId>\n");
        m_strResulst.append("        <ExportDate>" + ehm.getExportDate() + "</ExportDate>\n");
        m_strResulst.append("    </Header>\n");
    }

    void builderBody(vector < ExportDataModel*> & edmCollection) 
    {
        m_strResulst.append("    <Body>\n");
        for (vector<ExportDataModel*>::iterator iter = edmCollection.begin(); iter != edmCollection.end(); iter++) 
        {
            m_strResulst.append("        <id>" + (*iter)->getTransId() + "</id>\n");
            m_strResulst.append("        <amount>" + ConvertToString((*iter)->getQuantity()) + "</amount>\n");
        }
        m_strResulst.append("    </Body>\n");
    }
    void builderFoot(ExportFooterModel & efm) 
    {
        m_strResulst.append("    <Footer>\n");
        m_strResulst.append("        <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
        m_strResulst.append("    </Footer>\n</Receipt>\n");
    }

    string getResult() { return m_strResulst; }
public:
    XmlBuilder() { m_strResulst = ""; }
private:
    string m_strResulst;
};

class Director 
{
public:
    Director(Builder* pBuilder) : m_pBuilder(pBuilder) { }
    void construct(ExportHeaderModel& ehm, vector < ExportDataModel*>& edmCollection, ExportFooterModel& efm)
    {
        m_pBuilder->builderHeader(ehm);
        m_pBuilder->builderBody(edmCollection);
        m_pBuilder->builderFoot(efm);
    }
private:
    Builder* m_pBuilder;
};

int main(void)
{
    ExportHeaderModel* pEhm = new ExportHeaderModel("中國農行深圳支行", "4月30日");
    ExportDataModel* pEdm = new ExportDataModel("1", 10000.00f);
    ExportDataModel* pEdm2 = new ExportDataModel("2", 20000.00f);
    vector<ExportDataModel*> myVec;
    myVec.push_back(pEdm);
    myVec.push_back(pEdm2);
    ExportFooterModel* pEfm = new ExportFooterModel("備注:最終以銀行出具的正式回收機關準");

    Builder* pBuilder = new XmlBuilder();
    Director* pDirector = new Director(pBuilder);
    pDirector->construct(*pEhm, myVec, *pEfm);
    cout << pBuilder->getResult() << endl;

    cout << "----------------" << endl;

    Builder* pBuilder1 = new TxtBuilder();
    Director* pDirector1 = new Director(pBuilder1);
    pDirector1->construct(*pEhm, myVec, *pEfm);
    cout << pBuilder1->getResult() << endl;

    system("pause");
    return 0;
}
           

執行結果:

生成器模式(建造者模式 Builder)

設計模式系列 https://blog.csdn.net/nie2314550441/article/details/105849726

繼續閱讀