创建型模式—建造者模式

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

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

以上是关于创建型模式—建造者模式的主要内容,如果未能解决你的问题,请参考以下文章

(创建型模式)建造者模式

设计模式——创建型模式之建造者模式

JavaScript设计模式创建型设计模式--建造者模式

设计模式- 创建型模式, 建造者模式

设计模式创建型建造者模式

设计模式创建型建造者模式