设计模式学习–建造者模式

设计模式学习–建造者模式

文章理论部分参考以下链接

http://www.runoob.com/design-pattern/abstract-factory-pattern.html

一、建造者模式介绍

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。一个 Builder 类会一步一步构造最终的对象,该 Builder 类是独立于其他对象的。这种类型的设计模式属于创建型模式。
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
如何解决:将变与不变分离开。
关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。
应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的”套餐”。 2、JAVA 中的 StringBuilder。
优点: 1、建造者独立,易扩展。 2、便于控制细节风险。
缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。
使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。3、当构造过程必须允许被构造的对象有不同的表示时。
注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

这里写图片描述

**抽象基类:**Builder:这个基类是全部创建对象过程的抽象,提供构建不同组成部分的接口函数
接口:
1、Builder::BuildPart函数:是对一个对象不同部分的构建函数接口,由Builder的派生类来具体实现.
2、Director::Construct函数:通过调用上面的各个接口函数完成对象的构建。
也就是说各个不同部分装配的过程都是一致的(同样的调用的Construct函数),但是不同的构建方式会有不同的表示(根据Builder的实际类型来决定如何构建,也就是多态)
解析:
建造者模式是基于这样的一个情况:比如一辆单车,都是由车轮车座等等的构成的(一个对象不同的组成部分),不同的品牌生产出来的也不一样(不同的构建方式)。虽然不同的品牌构建出来的单车不同,但是构建的过程还是一样的。也就是说Construct函数中固定了各个组成部分的装配方式,而具体是装配怎样的组成部分由Builder的派生类实现。

二、实现演示

1、整体的代码,先出现UML结构图中对应的代码,熟悉该模式的过程。

#include<iostream>
using namespace std;

//虚拟基类,是所有Builder的基类,提供不同部分的构建接口函数
class Builder
{
public:
    Builder(){}
    virtual ~Builder(){}
    //纯虚函数,提供构建不同部分的构建接口函数
    virtual void BuilderPartA()=0;
    virtual void BuilderPartB()=0;
};

//使用Builder构建产品,构建产品的过程都一致,但是不同的builder有不同的实现这个不同的实现通过不同的Builder派生类来实现,存有一个Builder的指针,通过这个来实现多态调用
class Director
{
public:
    Director(Builder* pBuilder):m_pBuilder(pBuilder){}
    ~Director()
    {
    delete m_pBuilder;
    m_pBuilder = NULL;
    }

    // Construct函数表示一个对象的整个构建过程,不同的部分之间的装配方式都是一致的,首先构建PartA其次是PartB,只是根据不同的构建者会有不同的表示
    void Construct()
    {
        m_pBuilder->BuilderPartA();
        m_pBuilder->BuilderPartB();
    }
private:
    Builder* m_pBuilder;
};
//Builder的派生类,实现BuilderPartA和BuilderPartB接口函数
class ConcreteBuilder1:public Builder
{
public:
    ConcreteBuilder1(){}
    virtual ~ConcreteBuilder1(){}
    virtual void BuilderPartA()
    { 
        cout<<"BuilderPartA by ConcreteBuilder1"<<endl; 
    }
    virtual void BuilderPartB()
    { 
        cout<<"BuilderPartB by ConcreteBuilder1"<<endl; 
    }
};

//Builder的派生类,实现BuilderPartA和BuilderPartB接口函数
class ConcreteBuilder2:public Builder
{
public:
    ConcreteBuilder2(){}
    virtual ~ConcreteBuilder2(){}
    virtual void BuilderPartA()
    { 
        cout<<"BuilderPartA by ConcreteBuilder2"<<endl; 
    }
    virtual void BuilderPartB()
    { 
        cout<<"BuilderPartB by ConcreteBuilder2"<<endl;
    }
};

int main()
{
    Builder* pBuilder1 = new ConcreteBuilder1;
    Director* pDirector1 = new Director(pBuilder1);
    pDirector1->Construct();
    Builder* pBuilder2 = new ConcreteBuilder2;
    Director* pDirector2 = new Director(pBuilder2);
    pDirector2->Construct();
    delete pDirector1;
    delete pDirector2;
    return 0;
}

2、仿写一个的例子,这里将Runoob中的例子简化加改写。
假设一个快餐店的商业案例,其中,一个典型的套餐是一个汉堡、一杯饮料和一份薯条。其中汉堡可以是牛肉汉堡或鳕鱼汉堡等。而饮料可以是可口可乐,也可以奶茶。虽然种类很多,但最后组成的套路包含三个基本元素不变。

(1)首先创建了一个套餐的基类

//类似Builder基类,提供不同部分的构建接口函数
class Meal
{
public:
    Meal(){}
    virtual ~Meal(){}
    //纯虚函数,提供构建不同部分的构建接口函数
    virtual void Burger()=0;
    virtual void Drink()=0;                  
    virtual void Fries()=0;
};

(2)再创建了一个配餐员的类,它来把汉堡,饮料和薯条配齐。

class Director
{
public:
    Director(Meal* pMeal):m_pMeal(pMeal){}
    ~Director()
    {
    delete m_pMeal;
    m_pMeal = NULL;
    }

    // Construct函数表示一个对象的整个构建过程,不同的部分之间的装配方式都是一致的
    void Construct()
    {
        m_pMeal->Burger();
        m_pMeal->Drink();
        m_pMeal->Fries();
    }
private:
    Meal* m_pMeal;
};

(3)加入两款具体的套餐

//牛肉堡套餐
class BeefMeal:public Meal
{
public:
    BeefMeal(){}
    virtual ~BeefMeal(){}
    virtual void Burger()
    { 
        cout<<"Add a Beef Burger"<<endl; 
    }
    virtual void Drink()
    { 
        cout<<"Cola"<<endl; 
    }
    virtual void Fries()
    {
        cout<<"Fries"<<endl;
    }
};
//鳕鱼堡套餐
class FishMeal:public Meal
{
public:
    FishMeal(){}
    virtual ~FishMeal(){}
    virtual void Burger()
    { 
        cout<<"Add a Fish Burger"<<endl; 
    }
    virtual void Drink()    //奶茶配鱼肉
    { 
        cout<<"Milk Tea"<<endl; 
    }
    virtual void Fries()
    {
        cout<<"Fries"<<endl;
    }
};

(4)

int main()
{
    Director* pDirector1 = new Director(new BeefMeal);
    pDirector1->Construct();
    Director* pDirector2 = new Director(new FishMeal);
    pDirector2->Construct();
    delete pDirector1;
    delete pDirector2;

    return 0;
}

三、拓展性

如果想再新添,什么鸡肉堡套餐,只需要新加一个鸡肉堡套路的类(当然鸡肉堡这个实现也会新加,但这不考虑)。但是如果套餐的组成变了,比如说套餐中新加了鸡翅等,那需要修改的地方还是挺多的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值