C++设计模式之建造者模式(builder)(创建型)

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性:封装、继承、多态,真正领悟设计模式的精髓是可能一个漫长的过程,需要大量实践经验的积累。

建造者模式Buider(又叫生成器模式、构造者模式)是属于创建性的设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。主要用于一步一步创建一个较复杂的对象,通过使用Builder模式向用户隐藏内部构建的细节,专注于控制对象的组装流程,从而达到将构建复杂对象的过程和其他部件解耦,最终实现两个自由扩展构建流程和部件。

Builder模式和AbstractFactory模式在功能上很相似,因为都是用来创建大的复杂的对象,它们的区别是:Builder模式强调的是在导向者的控制下一步一步构造产品的,并通过相同的创建过程可以获得不同的结果对象,一般来说Builder模式中对象不是直接返回的。而在AbstractFactory模式中对象是直接返回的,AbstractFactory模式强调的是为创建多个相互依赖的对象提供一个同一的接口。创建者模式可以能更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

    对于客户来说,只需知道导向者就可以了,通过导向者,客户就能构造复杂的对象,而不需要知道具体的构造过程。

Builder模式的优点
使得建造代码与表示代码分离,具有良好的封装性和独立性,对客户隐藏了该产品是如何组装的,既产品内部的实现和组成细节模块之间相对独立,耦合度不高有利于程序扩展,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
Builder模式的缺点
由于产品自身的组成复杂和组成流程复杂,可能会产生额外的副产品,消耗额外的内存资源,比如说额外的Builder对象和Director对象等。

Builder模式场景

•复杂的对象内部构造间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。

•当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

•当构造过程必须允许被构造的对象有不同的表示时。

ULM图

构建模式的组成

抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
具体建造者(ConcreteBuilder)

1)实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。

2)定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建

3)  提供一个检索产品的接口

4)   构造一个使用Builder接口的对象即在指导者的调用下创建产品实例

指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。

产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。

Builder模式的主要效果:

1 ) 它使你可以改变一个产品的内部表示 Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。

2) 它将构造代码和表示代码分开 Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个Concrete Builder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。3 ) 它使你可对构造过程进行更精细的控制 Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

这里我们介绍一个制造玩具的简单例子,对于建造一个奥特曼和蜘蛛侠的玩具来说,建造流程是稳定的:头--->身体--->四肢。对于这两个产品来说,具体的实现可能不同。在这个例子里为了让不同的奥特曼有差别,在用户端可以通过输入参数来控制。

实现代码:

#include <iostream>
#include <vector>
#include <string>

//产品类有多个组件组成
class Product
{
public:
    //添加组件
    void add(const std::string& componentName)
    {
        components.emplace_back(componentName);
    }
    //移除组件
    void remove(const std::string& componentName)
    {
        for (auto iter = components.begin(); iter != components.end();)
        {
            if (*iter == componentName)
            {
                iter = components.erase(iter);
            }
            else
            {
                iter++;
            }
        }
    }
    //显示产品组件
    void show()
    {
        std::cout << "显示产品的组件:" << std::endl;
        for (const auto& item : components)
        {
            std::cout << item << std::endl;
        }
        std::cout << std::endl;
    }

private:
    std::vector<std::string> components;
};

//抽象建造者
class Builder
{
public:
    virtual void buildHead() = 0;   //构建头
    virtual void buildBody() = 0;   //构建身体
    virtual void buildLimbs() = 0;  //构建四肢
    virtual Product* getProduct() = 0;
    virtual ~Builder() = default;
};

//奥特曼具体构造者
class UltramanBuilder : public Builder
{
public:
    UltramanBuilder(
        const std::string head,
        const std::string body,
        const std::string limbs)
        : head{head}
        , body{body}
        , limbs{limbs}
    {
        std::cout << "创建奥特曼." << std::endl;
        ultraman = new Product();
    }
    ~UltramanBuilder()
    {
        delete ultraman;
    }
    void buildHead() override
    {
        ultraman->add("奥特曼头" + head);
    }
    void buildBody() override
    {
        ultraman->add("奥特曼身体" + body);
    }
    void buildLimbs() override
    {
        ultraman->add("奥特曼四肢" + limbs);
    }
    Product* getProduct() override
    {
        return ultraman;
    }
private:
    Product* ultraman;
    const std::string head;
    const std::string body;
    const std::string limbs;
};

//蜘蛛侠具体构造者
class SpidermanBuilder : public Builder
{
public:
    SpidermanBuilder()
    {
        std::cout << "创建蜘蛛侠." << std::endl;
        spiderman = new Product();
    }
    ~SpidermanBuilder()
    {
        delete spiderman;
    }
    void buildHead() override
    {
        spiderman->add("蜘蛛侠头");
    }
    void buildBody() override
    {
        spiderman->add("蜘蛛侠身体");
    }
    void buildLimbs() override
    {
        spiderman->add("蜘蛛侠四肢");
    }
    Product* getProduct() override
    {
        return spiderman;
    }
private:
    Product* spiderman;
};

//指挥者类
class Director
{
public:
    void Construct(Builder* builder)
    {
        builder->buildHead();
        builder->buildBody();
        builder->buildLimbs();
    }
};

//客户端
int main()
{
    Director* director = new Director();

    std::cout << "指挥者用UltramanBuilder的方法创建产品:";
    UltramanBuilder* ultramanBuilder = new UltramanBuilder("有两个犄角", "带有XX特能", "手握YY剑");
    director->Construct(ultramanBuilder);
    Product* ultraman = ultramanBuilder->getProduct();
    ultraman->show();
    std::cout << std::endl;


    std::cout << "指挥者用SpidermanBuilderr的方法创建产品:";
    SpidermanBuilder* spidermanBuilder = new SpidermanBuilder();
    director->Construct(spidermanBuilder);
    Product* spiderman = spidermanBuilder->getProduct();
    spiderman->show();
    std::cout << std::endl;

    delete director;
    delete ultramanBuilder;
    delete spidermanBuilder;

    return 0;
}

结果如下:

在这里UltramanBuilder和SpidermanBuilder两个具体创建者的构造函数不用,主要是为了说明,客户也可以通过传入参数来创建UltramanBuilder这样的产品,通过参数的不同就可以得到不同的细微差别的复杂对象。例如,创建不同的奥尔曼(不同奥特曼头,身体,四肢不同)。

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值