设计模式 c++版(5)——建造者模式

定义:

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


示例一:建造者模式(通用版)

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. 类图11-1

 

2. 类图说明:

在CarModel 中定义了一个 setSequence 方法,车辆模型的动作如何排布在 ArrayList 中定义。然后 run() 方法根据 sequence 定义的顺序完成指定的顺序动作

 

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. 优点:

  •  封装性。使用建造者模式可以使客户端不必知道产品内部组成的细节,如例子中我们不关心每一个具体模型的内部是怎样实现的,产生的对象类型就是CarModel。
  •  建造者独立,容易扩展。BenzBuilder 和 BMWBuilder 是相互独立的,对系统的扩展非常有利。
  •  便于控制细节风险。由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他模块产生任何影响。

 

2. 使用场景:

  •  相同的方法,不同的执行顺序,产生不同的时间结果时。
  •  多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时。
  •  产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能。
  •  在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时。该场景只是一个补偿方法,因为一个对象不容易获得,而在设计阶段竟然没有发觉。

 

3. 注意事项:

建造者模式关注的是零件类型和装配工艺(顺序),这是它与工厂方法模式最大的不同。

 


参考文献《秦小波. 设计模式之禅》(第2版) (华章原创精品) . 机械工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值