1. 程式人生 > >設計模式 c++版(7)——建造者模式

設計模式 c++版(7)——建造者模式

定義:即生成器模式,將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。

示例一:汽車模型擴充套件,根據不同的產品,執行任務的順序不同

1. 類圖說明:

在CarModel 中定義了一個 setSequence 方法,車輛模型的動作如何排布在 ArrayList 中定義。然後 run() 方法根據 sequence 定義的順序完成指定的順序動作

2. 汽車模型,類圖11-1

3. 汽車模型,程式碼清單11-1:  


////////    **********  1.車輛模型擴充套件 ,程式碼清單11-1:***************//

enum ESequence
{
    EStart  ,
    EStop   ,
    EAlarm  ,
    EEnginBoom
};


class CarModel
{
protected:
    virtual void    start()     = 0;
    virtual void    stop()      = 0;
    virtual void    alarm()     = 0;
    virtual void    enginBoom() = 0;

public:
    void    setSequence(QList<ESequence> list){this->m_list = list;}
    void    run()
    {
        QList<ESequence>::const_iterator iter = this->m_list.begin();
        while(iter != this->m_list.end())
        {
            switch (*iter)
            {
            case EStart:
                this->start();
                break;
            case EStop:
                this->stop();
                break;
            case EAlarm:
                this->alarm();
                break;
            case EEnginBoom:
                this->enginBoom();
                break;
            };
            ++iter;
        }
    }    

private:
    QList<ESequence> m_list;
};

class BenzModel:public CarModel
{
protected:
    virtual void    start()     {qDebug() << "BenzModel : start";}
    virtual void    stop()      {qDebug() << "BenzModel : stop";}
    virtual void    alarm()     {qDebug() << "BenzModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BenzModel : enginBoom";}
};

class BMWModel:public CarModel
{
protected:   
    virtual void    start()     {qDebug() << "BMWModel : start";}
    virtual void    stop()      {qDebug() << "BMWModel : stop";}
    virtual void    alarm()     {qDebug() << "BMWModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BMWModel : enginBoom";}
};

int main()
{
    CarModel *benz = new BenzModel();
    QList<ESequence> list;
    list.clear();
    list.push_back(EEnginBoom);
    list.push_back(EAlarm);
    list.push_back(EStart);
    list.push_back(EStop);
    
    benz->setSequence(list);
    benz->run();
    
    delete benz;
    return 0;
}

示例二:汽車模型擴充套件,增加需求:動作執行順序可以隨意調整

1. 類圖11-2

2. 類圖說明:

增加了一個CarBuilder 抽象類,用來組裝各個車模,需要什麼型別什麼順序的車輛模型,都由相關的子類完成。

3. 模板方法模式,程式碼清單11-2:  


////////    **********  2.車輛模型擴充套件 ,程式碼清單11-2:***************//

enum ESequence
{
    EStart  ,
    EStop   ,
    EAlarm  ,
    EEnginBoom
};

class CarModel
{
protected:
    virtual void    start()     = 0;
    virtual void    stop()      = 0;
    virtual void    alarm()     = 0;
    virtual void    enginBoom() = 0;

public:
    void    setSequence(QList<ESequence> list){this->m_list = list;}
    void    run()
    {
        QList<ESequence>::const_iterator iter = this->m_list.begin();
        while(iter != this->m_list.end())
        {
            switch (*iter)
            {
            case EStart:
                this->start();
                break;
            case EStop:
                this->stop();
                break;
            case EAlarm:
                this->alarm();
                break;
            case EEnginBoom:
                this->enginBoom();
                break;
            };
            ++iter;
        }
    }    
    
private:
    QList<ESequence> m_list;
};

class BenzModel:public CarModel
{
protected:
    virtual void    start()     {qDebug() << "BenzModel : start";}
    virtual void    stop()      {qDebug() << "BenzModel : stop";}
    virtual void    alarm()     {qDebug() << "BenzModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BenzModel : enginBoom";}
};

class BMWModel:public CarModel
{
protected:   
    virtual void    start()     {qDebug() << "BMWModel : start";}
    virtual void    stop()      {qDebug() << "BMWModel : stop";}
    virtual void    alarm()     {qDebug() << "BMWModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BMWModel : enginBoom";}
};

class CarBuilder
{
public:
    virtual void        setSequence(QList<ESequence> list) = 0;
    virtual CarModel*   getCarModel()                      = 0;
};

class BenzBuilder: public CarBuilder
{
public:
    BenzBuilder()       {m_benz =  new BenzModel();}
    ~BenzBuilder()      {delete m_benz;}
    virtual void        setSequence(QList<ESequence> list){this->m_benz->setSequence(list);}
    virtual CarModel*   getCarModel()                     
    {
        CarModel  *car = dynamic_cast<CarModel*>(m_benz);
        return car;
    }
    
private:
    BenzModel *m_benz;
};

class BMWBuilder: public CarBuilder
{
public:
    BMWBuilder()       {m_bmw =  new BMWModel();}
    ~BMWBuilder()      {delete m_bmw;}
    virtual void        setSequence(QList<ESequence> list){this->m_bmw->setSequence(list);}
    virtual CarModel*   getCarModel()                     
    {
        CarModel  *car = dynamic_cast<CarModel*>(m_bmw);
        return car;
    }
private:
    BMWModel *m_bmw;
};

int main()
{
    //benz
    QList<ESequence> list;
    list.clear();
    list.push_back(EEnginBoom);
    list.push_back(EAlarm);
    list.push_back(EStart);
    list.push_back(EStop);
    
    BenzBuilder benzBuilder;
    BenzModel *benz;
    
    benzBuilder.setSequence(list);
    benz = dynamic_cast<BenzModel*>(benzBuilder.getCarModel());
    benz->run();
    
    //bmw
    QList<ESequence> list2;
    list2.clear();
    list2.push_back(EStop);
    list2.push_back(EAlarm);
    list2.push_back(EStart);
    list2.push_back(EEnginBoom);
    
    BMWBuilder bmwBuilder;
    BMWModel *bmw;
    
    bmwBuilder.setSequence(list2);
    bmw = dynamic_cast<BMWModel*>(bmwBuilder.getCarModel());
    bmw->run();

    return 0;
}

示例三:汽車模型擴充套件,增加需求:根據不同的給定順序進行生產

1. 模板方法模式通用類圖,類圖11-3

2. 類圖說明:

增加了一個 Director 類,負責按照指定的順序生產模型

3. 結構說明:

getABenzModel 方法:元件出A型號的賓士車模型,其過程為只有start 、stop ;沒有engineboom 、alarm 。 getBBenzModel 方法:元件出B型號的賓士車模型,其過程為 engineboom → start → stop ;沒有alarm 。 getCBMWModel 方法:元件出C型號的寶馬車模型,其過程為 alarm → start → stop ,沒有engineboom getDBMWModel 方法:元件出D型號的寶馬車模型,其過程為 start ; 沒有engineboom 、alarm 、stop

3. 模板方法模式,程式碼清單11-3:  

////////    **********  3.車輛模型擴充套件 ,程式碼清單11-3:***************//


enum ESequence
{
    EStart  ,
    EStop   ,
    EAlarm  ,
    EEnginBoom
};

class CarModel
{
protected:
    virtual void    start()     = 0;
    virtual void    stop()      = 0;
    virtual void    alarm()     = 0;
    virtual void    enginBoom() = 0;

public:
    void    setSequence(QList<ESequence> list){this->m_list = list;}
    void    run()
    {
        QList<ESequence>::const_iterator iter = this->m_list.begin();
        while(iter != this->m_list.end())
        {
            switch (*iter)
            {
            case EStart:
                this->start();
                break;
            case EStop:
                this->stop();
                break;
            case EAlarm:
                this->alarm();
                break;
            case EEnginBoom:
                this->enginBoom();
                break;
            };
            ++iter;
        }
    }    
    
private:
    QList<ESequence> m_list;
};

class BenzModel:public CarModel
{
protected:
    virtual void    start()     {qDebug() << "BenzModel : start";}
    virtual void    stop()      {qDebug() << "BenzModel : stop";}
    virtual void    alarm()     {qDebug() << "BenzModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BenzModel : enginBoom";}
};

class BMWModel:public CarModel
{
protected:   
    virtual void    start()     {qDebug() << "BMWModel : start";}
    virtual void    stop()      {qDebug() << "BMWModel : stop";}
    virtual void    alarm()     {qDebug() << "BMWModel : alarm";}
    virtual void    enginBoom() {qDebug() << "BMWModel : enginBoom";}
};

class CarBuilder
{
public:
    virtual void        setSequence(QList<ESequence> list) = 0;
    virtual CarModel*   getCarModel()                      = 0;
};

class BenzBuilder: public CarBuilder
{
public:
    BenzBuilder()       {m_benz =  new BenzModel();}
    ~BenzBuilder()      {delete m_benz;}
    virtual void        setSequence(QList<ESequence> list){this->m_benz->setSequence(list);}
    virtual CarModel*   getCarModel()                     
    {
        CarModel  *car = dynamic_cast<CarModel*>(m_benz);
        return car;
    }
    
private:
    BenzModel *m_benz;
};

class BMWBuilder: public CarBuilder
{
public:
    BMWBuilder()       {m_bmw =  new BMWModel();}
    ~BMWBuilder()      {delete m_bmw;}
    virtual void        setSequence(QList<ESequence> list){this->m_bmw->setSequence(list);}
    virtual CarModel*   getCarModel()                     
    {
        CarModel  *car = dynamic_cast<CarModel*>(m_bmw);
        return car;
    }
private:
    BMWModel *m_bmw;
};

//導演類
class Director
{
public:
    Director()
    {
        m_benzBuilder = new BenzBuilder();
        m_bmwBuilder  = new BMWBuilder();
    }
    ~Director()
    {
        delete this->m_benzBuilder;
        delete this->m_bmwBuilder;
    }
    
    BenzModel* getABenzModel()
    {
        this->m_list.clear();
        this->m_list.push_back(EStart);
        this->m_list.push_back(EStop);
        this->m_benzBuilder->setSequence(this->m_list);
        BenzModel *model = dynamic_cast<BenzModel*>(m_benzBuilder->getCarModel());
        return model;
    }
    
    BenzModel* getBBenzModel()
    {
        this->m_list.clear();
        this->m_list.push_back(EEnginBoom);
        this->m_list.push_back(EStart);
        this->m_list.push_back(EStop);
        this->m_benzBuilder->setSequence(this->m_list);
        BenzModel *model = dynamic_cast<BenzModel*>(m_benzBuilder->getCarModel());
        return model;
    }
    
    BMWModel* getCBMWModel()
    {
        this->m_list.clear();
        this->m_list.push_back(EAlarm);
        this->m_list.push_back(EStart);
        this->m_list.push_back(EStop);
        this->m_bmwBuilder->setSequence(this->m_list);
        BMWModel *model = dynamic_cast<BMWModel*>(m_bmwBuilder->getCarModel());
        return model;
    }
    
    BMWModel* getDBMWModel()
    {
        this->m_list.clear();
        this->m_list.push_back(EStart);
        this->m_bmwBuilder->setSequence(this->m_list);
        BMWModel *model = dynamic_cast<BMWModel*>(m_bmwBuilder->getCarModel());
        return model;
    }
    
private:
    QList<ESequence>  m_list;
    BenzBuilder      *m_benzBuilder;
    BMWBuilder       *m_bmwBuilder;
};

int main()
{
    Director director;
    //生產2輛A型別賓士車
    for (int i = 0; i < 2; ++i){director.getABenzModel()->run();}
    
    //3輛B型別賓士車
    for (int i = 0; i < 3; ++i){director.getBBenzModel()->run();}
    
    //4輛C型別寶馬車
    for (int i = 0; i < 4; ++i){director.getCBMWModel()->run();}
    
    return 0;
}


示例四:建造者模式的通用版本

1. 建造者模式的通用版本,類圖11-4

2. 類圖說明:

在建造者模式中,有如下4個角色: Product 產品類: 通常是實現了模板方法模式,也就是有模板方法和基本方法。例子中的 BenzModel 和 BMWModel就屬於產品類。 Builder 抽象建造者:規範產品的元件,一般是由子類實現。例子中的CarBuilder 就屬於抽象建造者。 ConcreteBuilder 具體建造者:實現抽象類定義的所有方法,並且翻譯一個組建好的物件。例子中的 BenzBuilder 和 BMWBuilder 就屬於具體建造者。 Director 導演類:負責安排已有模組的順序,然後告訴Builder開始建造。

3. 建造者模式的通用版本,程式碼清單11-4:  

//////////    **********  4.建造者模式的通用版本 ,程式碼清單11-4:***************//

class Product
{
public:
    void    doSomething(){qDebug() << "***";}
};

class Builder
{
public:
    virtual void        setPart()      = 0;
    virtual Product*    buildProduct() = 0;
};

class ConcreteProduct: public Builder
{
public:
    ConcreteProduct() {this->m_product = new Product();}
    ~ConcreteProduct(){delete this->m_product;}
    void    setPart(){} //產品類內的邏輯處理
    Product*    buildProduct()
    {
        return this->m_product;
    }
    
private:
    Product*    m_product;
};

class Director
{
public:
    Director() {this->m_builder = new ConcreteProduct();}
    ~Director(){delete this->m_builder;}
    Product*  getAProduct()
    {
        this->m_builder->setPart();
        Product* product = dynamic_cast<Product*>(this->m_builder->buildProduct());
        
        return product;
    }
    
private:
    ConcreteProduct *m_builder;
};

int main ()
{
    Director director;
    director.getAProduct()->doSomething();
    
    return 0;
}

三、建造者模式的應用

1. 優點:

  •  封裝性。使用建造者模式可以使客戶端不必知道產品內部組成的細節,如例子中我們不關心每一個具體模型的內部是怎樣實現的,產生的物件型別就是CarModel。
  •  建造者獨立,容易擴充套件。BenzBuilder 和 BMWBuilder 是相互獨立的,對系統的擴充套件非常有利。
  •  便於控制細節風險。由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他模組產生任何影響。

2. 使用場景:

  •  相同的方法,不同的執行順序,產生不同的時間結果時。
  •  多個部件或零件,都可以裝配到一個物件中,但是產生的執行結果又不相同時。
  •  產品類非常複雜,或者產品類中的呼叫順序不同產生了不同的效能。
  •  在物件建立過程中會使用到系統中的一些其他物件,這些物件在產品物件的建立過程中不易得到時。該場景只是一個補償方法,因為一個物件不容易獲得,而在設計階段竟然沒有發覺。

3. 注意事項:

建造者模式關注的是零件型別和裝配工藝(順序),這是它與工廠方法模式最大的不同。

參考文獻《秦小波. 設計模式之禪》(第2版) (華章原創精品) . 機械工業出版社