创建型模式—建造者模式
Posted 浅墨浓香
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型模式—建造者模式相关的知识,希望对你有一定的参考价值。
1. 建造者(Builder,或生成器)模式的定义
(1)将一个复杂对象构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
①上述提到的“构建”是指构造过程的算法(即构造顺序,位于director类中),“表示”指生成各部件的具体细节(或叫实现,位于Builder或其子类中)。
②由指导者(director)来指导构造过程,而建造者(builder)负责每步的对象的具体实现和组装各部件。
③指导者可以重用构建过程,而生成器是可以被切换的具体实现。
(2)建造者模式的结构和说明
①Builder:建造者接口,定义创建一个Product对象所需要的各个部件的接口。
②ConcreteBuilder:具体的建造者实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
③Director:指导员,主要用来使用Builder接口,以一个统一年过程来构建所需要的Product对象。
④Product:产品,表示被建造者构建的复杂对象,包含多个部件。
2. 建造者模式的思考
(1)建造者模式的功能:构建复杂的产品,而且是细化的、分步骤的构建产品。也就是其重在一步一步解决构造复杂对象的问题。
①构建的过程是统一的、固定不变的(则指导者来制定)。变化的是的每步的具体的实现,由建造者来实现。
②建造者模式的重心在于分离构建算法和具体构造的实现。
(2)建造者模式的构成——两个部分
①Builder接口:这里定义了如何构建各个部件,也就是知道每个部件的功能是如何实现的,以及如何装配这些部件到产品中去。即部件构造和产品装配。
②Director:知道按什么流程来构建产品,负责整体的构建算法,通常是分步骤来执行。这里要强调的是,整体构建算法是固定的。当Director实现整体构建算法的时候,遇到需要创建和组合具体部件的时候,就会把这些具体的实现委托给Builder去完成。
【编程实验】建造神舟飞船
//创建型模式:建造者模式 //神舟飞船的组装 #include <stdio.h> #include <string> using namespace std; //*************************辅助类:各个部件************************ //轨道舱 class OrbitalModule { private: string name; public: OrbitalModule(string name) { this->name = name; } void setName(string name) { this->name = name; } string getName(){return name;} }; //发动机 class Engine { private: string name; public: Engine(string name) { this->name = name; } void setName(string name) { this->name = name; } string getName(){return name;} }; //逃逸塔 class EscapeTower { private: string name; public: EscapeTower(string name) { this->name = name; } void setName(string name) { this->name =name; } string getName(){return name;} }; //最终产品Product class Airship { private: OrbitalModule* orbitalModule; //轨道舱 Engine* engine; //发动机 EscapeTower* escapeTower; //逃逸塔 public: OrbitalModule* getOrbitalModule(){return orbitalModule;} void setOrbitalModule(OrbitalModule* orbitalModule) { this->orbitalModule =orbitalModule; } Engine* getEngine(){return engine;} void setEngine(Engine* engine) { this->engine =engine; } EscapeTower* getEscapeTower(){return escapeTower;} void setEscapeTower(EscapeTower* escapeTower) { this->escapeTower =escapeTower; } void launch() { //检测发动机是否正常 printf("%s\\n",engine->getName().c_str()); //检测轨道舱是否正常 printf("%s\\n",orbitalModule->getName().c_str()); //检测逃逸塔是否正常 printf("%s\\n",escapeTower->getName().c_str()); //发射 printf("launch...\\n"); } }; //*******************************************Builder:建造者***************************** //抽象建造者 class AirshipBuilder { public: //构建发动机 virtual void buildEngine() = 0; //构建轨道舱 virtual void buildOrbitalModule() = 0; //构建逃逸塔 virtual void buildEscapeTower() = 0; }; //具体建造者 class ConcreteAirshipBuilder : public AirshipBuilder { private: Airship airship; public: //Engine部件的构建 void buildEngine() { Engine* engine =airship.getEngine(); if (engine != NULL) delete engine; engine = new Engine("Airship\'s Engine!"); //组装工作 airship.setEngine(engine); } //OrbitalModule部件的构建 void buildOrbitalModule() { OrbitalModule* orbitalModule =airship.getOrbitalModule(); if (orbitalModule != NULL) delete orbitalModule; orbitalModule = new OrbitalModule("Airship\'s OrbitalModule!"); //组装工作 airship.setOrbitalModule(orbitalModule); } //EscapeTower部件的构建 void buildEscapeTower() { EscapeTower* escapeTower =airship.getEscapeTower(); if (escapeTower != NULL) delete escapeTower; escapeTower = new EscapeTower("Airship\'s EscapeTower!"); //组装工作 airship.setEscapeTower(escapeTower); } //返回最终的整个产品(神舟飞船) Airship& getResult(){return airship;} ~ConcreteAirshipBuilder() { OrbitalModule* orbitalModule = airship.getOrbitalModule(); if (orbitalModule != NULL) delete orbitalModule; Engine* engine =airship.getEngine(); if (engine != NULL) delete engine; EscapeTower* escapeTower = airship.getEscapeTower(); if (escapeTower != NULL) delete escapeTower; } }; //********************************Director:指导者****************************** class Director { private: AirshipBuilder* builder; public: Director(AirshipBuilder* builder) { this->builder = builder; } //构建过程 //1、建造者所构建的各部分是可以是先后顺序的,但本例这个顺序不明显或无关紧要。 //2、本类中只有构建的过程(流程,也就算法),组装过程放在Builder类中。 void construct() { //1.先构建发动机 builder->buildEngine(); //2.再构建轨道舱 builder->buildOrbitalModule(); //3.最后构建逃逸塔 builder->buildEscapeTower(); } }; int main() { //客户端调用例子 //构建者 AirshipBuilder* builder = new ConcreteAirshipBuilder(); //指导者 Director* director = new Director(builder); director->construct(); //生成最终产品 //测试 Airship& airship = ((ConcreteAirshipBuilder*)builder)->getResult(); airship.launch(); delete builder; delete director; return 0; }
3. 建造者模式的实现
(1)建造者的实现
①Builder接口的实现中,每个buildPart方法中可以包含创建部件对象和组装部件的功能。
②如果实现Builder时,只创建对象,没有组装功能,这里Builder实现跟抽象工厂的实现很类似。这时的Builder接口就类似于抽象工厂的接口。Builder的具体实现就类似于具体的工厂。从这点上看,Builder与抽象工厂很类似。
(2)指导者的实现
①指导者承担的是整体构建算法的部分,是相对不变的部分。因此在实现指导者的时候,把变化的部分分离出去是很重要的。
②指导员分离出去的变化部分,就到了建造者那里,指导者知道整体的构建算法,却不知道如何具体的创建和装配部件对象。
③在指导者的实现可以有较为复杂的算法和运算过程,在运算过程中根据需要,才会调用建造者的方法来生成部件对象。
(3)指导者和建造者的交互
①指导者和建造者一般是通过Builder的buildPart方法来进行交互的。
②实际开发中,指导者可以按整体构建算法的步骤进行运算。到了某一步骤,需要具体创建某个部件对象了,再调用Builder中创建相应部件的方法来创建具体部件。同时把前面运算的数据传递给Builder,因为Builder内部实现创建和组装部件的时候,可能会用到这些数据。
③Builder创建完具体的部件对象后,会把创建好的部件对象返回指导者。指导者继续后续的算法运算,如此反复下去,直到最终产品对象创建完毕。
(4)返回装配好的产品的方法
①标准的生成器模式中,在Builder实现里面会提供一个返回装配好的产品的方法,在Builder接口上是没有的。它考虑的是最终的对象一定要通过部件构建和装配,才算真正创建了。
②虽然指导者也参与其中,但它不负再具体部件的创建和组装,因此客户端是从Builder的实现里面获取最终装配好的产品。但也可以把这个方法加到Builder接口中。
4. 建造者模式的优点
(1)松散耦合
用同一个构建算法构建出表现上完全不同的产品,实现产品构建和产品表现上的分离。Builder模式中构建算法可以复用,而具体产品表现可以灵活、方便地扩展和切换。
(2)很容易改变产品的内部表示
建造者只提供接口给Director使用,具体的部件创建和装配方式被Builder接口隐藏了,Director并不知道实现的细节。这样要改变产品的内部表示,只需要切换Builder的具体实现即可。不用管Director。
(3)更好的复用:Director中构建产品过程的算法相对固定,可以复用。
5. Builder模式的使用场合
(1)相同的方法,不同的执行顺序,产生不同的事件结构时,可以采用建造者模式。
(2)多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。
(3)产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个可以使用该模式。
6. 其他
(1)Builder与FactoryMethod模式结合
在Builder的实现中,通常需要选择具体的部件实现,这时可以用工厂方法来实现,通过工厂方法来获取具体的部件对象,然后再进行部件的装配。
(2)Builder与抽象工厂模式的区别
①Builder模式着重于一步步构造一个复杂对象,而Abstract Factory着重于多个系列的产品对象(简单的或复杂的)
②Builder是最后一步返回产品,而Abstract Factory是立即返回产品
③抽象工厂侧重点是创建,创建零件是它的主要职责,他关心的是创建产品的结果,而builder侧重的是创建产品的过程,即顺序安排。
(3)Builder与模板方法的区别
①两者都是定义了方法执行的流程。但一个前者是在Director定义的,后者是在父类定义的。
②在实现方法的结构上,建造者模式中使用的是组合的方式,而模板方法模式采用的是继承的方式
③模板方法模式是通过把不变行为搬移到父类(超类),去除了类中的重复代码来体现它的优势。而建造者是将不变部分移到Director中去,变化的部分由Builder接口去实现。
【编程实验】将数据导出为txt和xml格式的文件
①文件头:包括部门ID、导出数据的日期
②文件体:表名称、分条描述数据
③文件尾:输出人的信息
//创建型模式:建造者模式 //将数据导出为不同格式的文件 #include <iostream> #include <string> #include <sstream> #include <list> using namespace std; //*************************辅助类:各个部件************************ //文件头对象 class Header { private: string depId; //部门编号 string date; //导出数据的日期 public: void setDepId(string depId) { this->depId = depId; } string& getDepId(){return depId;} void setDate(string date) { this->date = date; } string& getDate(){return date;} }; //文件体 class Body { private: string productId; //产品编号 double price; //销售价格 double amount; //销售数量 public: void setProductId(string productId) { this->productId = productId; } string& getProductId(){return productId;} void setPrice(double price) { this->price = price; } double getPrice(){return price;} void setAmount(double amount) { this->amount = amount; } double getAmount(){return amount;} }; //文件尾 class Footer { private: string user; //输出人 public: void setUser(string user) { this->user = user; } string& getUser(){return user;} }; //*******************************Builder************************* class Builder { public: virtual void buildHeader(Header& header) = 0; virtual void buildBody(list<Body>& bodys) = 0; virtual void buildFooter(Footer& footer) = 0; }; //XmlBuilder class XmlBuilder : public Builder { private: string buffer; //用来记录文件的内容,相当于最终产品 public: void buildBody(list<Body>& bodys) { buffer.append(" <Body>\\n"); buffer.append(" <Datas TableName=Sale Details:>\\n"); list<Body>::iterator first = bodys.begin(); list<Body>::iterator last = bodys.end(); ostringstream oss; while (first != last) { oss.str(""); oss<<first->getPrice(); buffer.append(" <Data>\\n"); buffer.append(" <ProductId>"+first->getProductId()+"</ProductId>\\n"); buffer.append(" <Price>"+oss.str()+"</Price>\\n"); oss.str(""); oss<<first->getAmount(); buffer.append(" <Amount>"+oss.str()+"</Amount>\\n"); buffer.append(" </Data>\\n"); ++first; } buffer.append(" </Datas>\\n"); buffer.append(" </Body>\\n"); }; void buildFooter(Footer& footer) { buffer.append(" <Footer>\\n"); buffer.append(" <ExportUser>"+footer.getUser()+"\\n"); buffer.append(" </Footer>\\n"); buffer.append("</Report>\\n"); } void buildHeader(Header& header) { buffer.append("<?xml version =\'1.0\' encoding =\'gb2312\'?>\\n"); buffer.append("<Report>\\n"); buffer.append(" <Header>\\n"); buffer.append(" <DepId>"+header.getDepId()+"</DepId>\\n"); buffer.append(" <ExportDate>"+header.getDate()+"</ExportDate>\\n"); buffer.append(" </Header>\\n"); } string& getResult(){return buffer;} }; //TxtBuilder class TxtBuilder : public Builder { private: string buffer; //用来记录文件的内容,相当于最终产品 public: void buildBody(list<Body>& bodys) { list<Body>::iterator first = bodys.begin(); list<Body>::iterator last = bodys.end(); buffer.append("Sale details:\\n"); ostringstream oss; while (first != last) { buffer.append("ProductId="+first->getProductId()+", "); oss.str(""); oss << first->getPrice(); buffer.append("Price=" + oss.str()+", "); oss.str(""); oss << first->getAmount(); buffer.append("Amount=" + oss.str()+"\\n"); ++first; } } void buildFooter(Footer& footer) { buffer.append(footer.getUser()); } void buildHeader(Header& header) { buffer.append(header.getDepId()+","+header.getDate() + \'\\n\'); } string& getResult(){return buffer;} }; //*********************************Director********************* class Director { private: Builder* builder; public: Director(Builder* builder){this->builder = builder;} void construct(Header& header,list<Body>& bodys,Footer& footer) { builder->buildHeader(header); builder->buildBody(bodys); builder->buildFooter(footer); } }; int main() { //客户端调用例子 //准备测试数据 Header* header = new Header(); header->setDepId("one company"); header->setDate("2016-5-18"); list<Body> bodys; Body* body1 = new Body(); body1->setProductId("001"); body1->setPrice(100); body1->setAmount(80); Body* body2 = new Body(); body2->setProductId("002"); body2->setPrice(99); body2->setAmount(55); bodys.push_back(*body1); bodys.push_back(*body2); Footer* footer = new Footer(); footer->setUser("SantaClaus"); //测试输出到文本文件 TxtBuilder* txtBuilder = new TxtBuilder(); //创建指导者对象 Director* directorTxt = new Director(txtBuilder); directorTxt->construct(*header,bodys,*footer); cout << txtBuilder->getResult() << endl; //测试输出到XML文件 XmlBuilder* xmlBuilder = new XmlBuilder(); //创建指导者对象 Director* directorXml = new Director(xmlBuilder); directorXml->construct(*header,bodys,*footer); cout << xmlBuilder->getResult() << endl; delete txtBuilder; delete directorTxt; delete xmlBuilder; delete directorXml; delete header; delete body1; delete body2; delete footer; return 0; }
以上是关于创建型模式—建造者模式的主要内容,如果未能解决你的问题,请参考以下文章