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

设计模式系列

Builder(生成器)——对象创建模式

1.意图

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

 

2.适用性

  • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  • 当创建过程必须允许被构造的对象有不同的表示时。

 

3.结构

 

4.参与者

  • Builder

—— 为创建一个Product对象的各个部件指定抽象接口

  • ConcreteBuilder

—— 实现Builder的接口以构造和装配该产品的各个部件

—— 定义并明确它所创建的表示

—— 提供一个检索产品的接口

  • Director

—— 构造一个可以使用Builder接口的对象

  • Product

—— 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程

—— 包含定义组成部件的类,包含将这些部件装配成最终产品的接口

 

5.协作

  • 客户创建Director对象,并用它所想要的Builder对象进行配置
  • 一旦产品部件被生成,导向器就会通知生成器
  • 生成器处理导向器的请求,并将部件添加到该产品中
  • 客户从生成器中检索产品

下面的交互图说明了Builder和Director是如何与一个客户协作的

 

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;
}

执行结果:

设计模式系列 https://blog.csdn.net/nie2314550441/article/details/105849726

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值