目录
Builder构建者模式:场景、功能、组成部分
场景
还是老套路,首先不用设计模式来实现这个功能:
#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 getStrDepId() {
return m_strDepId;
}
string getStrExportDate() {
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 getStrTransId() { 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 ExportToTextHelper {
public:
void doExport(ExportHeaderModel& ehm, vector<ExportDataModel*>edmCollection, ExportFooterModel& efm) {
string strTemp = "";
//第一步:写文件头
strTemp += ehm.getStrDepId() + "," + ehm.getStrExportDate() + "\n";
//第二部:写文件体数据
for (auto it = edmCollection.begin(); it != edmCollection.end(); it++) {
strTemp += (*it)->getStrTransId() + ":" + ConvertToString((*it)->getQuantity()) + "\n";
}
//第三步:拼接文件尾
strTemp += efm.getExportUser() + "\n";
cout << strTemp << endl;
}
};
class ExportToXmlHelper {
public:
void doExport(ExportHeaderModel& ehm, vector<ExportDataModel*>edmCollection, ExportFooterModel& efm) {
string strTemp = "";
//第一步:拼接文件头
strTemp.append("<?xml version='1.0' enconding='utf-8'>\n ");
strTemp.append("<Recipt>\n");
strTemp.append(" <Header>\n");
strTemp.append(" <DepId>");
strTemp.append(ehm.getStrDepId() + "</DepId>\n");
strTemp.append(" <ExportData>" + ehm.getStrExportDate() + "</ExportData>\n");
strTemp.append(" </Header>\n");
//第二部:构建数据体
strTemp.append(" <Body>\n");
for (auto it = edmCollection.begin(); it != edmCollection.end(); it++) {
strTemp.append(" <id>" + (*it)->getStrTransId() + "</id>\n");
strTemp.append(" <amount>" + ConvertToString((*it)->getQuantity()) + "</amount>\n");
}
strTemp.append(" </Body>\n");
//第三步:拼接文件尾
strTemp.append(" <Footer>\n");
strTemp.append(" <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
strTemp.append(" </Footer>\n</Recipt>\n");
cout << strTemp << endl;
}
};
int main() {
ExportHeaderModel* pEhm = new ExportHeaderModel("南京1支行", "1st June");
ExportDataModel* pEdm1 = new ExportDataModel("1", 10000.0f);
ExportDataModel* pEdm2 = new ExportDataModel("2", 20000.0f);
vector<ExportDataModel*>Vec;
Vec.push_back(pEdm1);
Vec.push_back(pEdm2);
ExportFooterModel* pEfm = new ExportFooterModel("yxh");
ExportToTextHelper helper1;
helper1.doExport(*pEhm, Vec, *pEfm);
ExportToXmlHelper helper2;
helper2.doExport(*pEhm, Vec, *pEfm);
return 0;
}
不错,但有一个问题,两种Helper中都存在着相同的步骤一二三。
既然都学了设计模式了,这种重复性的代码必然是不符合高逼格的,肯定要重构!
这里就引出了Builder模式
#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 getStrDepId() {
return m_strDepId;
}
string getStrExportDate() {
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 getStrTransId() { 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 TextBuilder :public Builder {
public:
void builderHeader(ExportHeaderModel& ehm) {
m_strResult.append(ehm.getStrDepId() + "," + ehm.getStrExportDate() + "\n");
}
void builderBody(vector<ExportDataModel*>& edmCollection) {
for (auto it = edmCollection.begin(); it != edmCollection.end(); it++) {
m_strResult += (*it)->getStrTransId() + ":" + ConvertToString((*it)->getQuantity()) + "\n";
}
}
void builderFoot(ExportFooterModel& efm) {
m_strResult += efm.getExportUser() + "\n";
}
string getResult() {
return m_strResult;
}
public:
TextBuilder() { m_strResult = ""; }
private:
string m_strResult;
};
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() {
ExportHeaderModel* pEhm = new ExportHeaderModel("南京1支行", "1st June");
ExportDataModel* pEdm1 = new ExportDataModel("1", 10000.0f);
ExportDataModel* pEdm2 = new ExportDataModel("2", 20000.0f);
vector<ExportDataModel*>Vec;
Vec.push_back(pEdm1);
Vec.push_back(pEdm2);
ExportFooterModel* pEfm = new ExportFooterModel("yxh");
Builder* pBuilder = new TextBuilder();
Director* pDirector = new Director(pBuilder);
pDirector->construct(*pEhm, Vec, *pEfm);
cout << pBuilder->getResult() << endl;
return 0;
}
这里只重构了Text的创建。
其实总体看来,设计模式的目的就是:把不变的给客户,把以后可能变化的留给开发者,并且要便于开发者增加功能模块,要达到模块于模块之间的松耦合。
功能
- 构建复杂产品,而且是细化的,分步骤的构建产品,重在解决一步一步构造复杂对象的问题
- 这个构建过程是统一的,固定不变的,变化的部分就放到生成器Builder中
- 只要配置不同的Builder,那么同样的构建过程,就能构建出不同的产品出来
组成部分:Builer+Director
- Builder接口,定义如何构建各个部件,每个部件功能如何实现,如何装配这些部件到产品中去
- Director,定义如何组合来构建产品,负责整体的构建算法,通常分步骤来执行