站点图标

设计模式 06 生成器模式

一、意图

  将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  人话:工厂流水线生成产品。

图1:builder示意图

图1:builder示意图[/caption]

二、问题

  下面我们来考虑如何创建一个房屋对象。我们可以考虑抽象出房屋的基本特征,然后按用户不同的需求添加不同的属性,从而产生不同的子类。

图2:使用继承的方式来创建房屋

图2:使用继承的方式来创建房屋[/caption]
  但是这么做将会产生相当多的子类。另一个解决方法是在基类中写一个巨大的构造函数,在创建时指定需要哪些元素。
图3:使用构造函数参数化的方式来创建房屋

图3:使用构造函数参数化的方式来创建房屋[/caption]
  但是这一做法使得我们的构造函数很不简洁,同时有的参数很少会被用到。例如,只有很少的房屋才会有游泳池。

三、解决方案

3.1 生成器模式

  生成器模式建议将构造对象的代码从产品中抽离,并单独放在一个名为生成器的对象当中。该模式将构造对象过程划分为一组步骤,如 buildWalls创建墙壁 和 buildDoor创建房门 等。每次创建对象时,都需要通过生成器执行一些列步骤。重点在于无需调用全部的步骤,而只需调用创建特定对象配置所需的那些步骤即可。

图4:生成器分离创建复杂对象的步骤

图4:生成器分离创建复杂对象的步骤[/caption]
  当你需要创建不同形式的产品时,其中的一些构造步骤可能需要不同的实现。例如,木屋的房门可能需要使用木头制造,而城堡的房门则必须使用石头制造。在这种情况下,你可以创建多个不同的生成器,用不同方式实现一组相同的创建步骤。然后你就可以在创建过程中使用这些生成器(例如按顺序调用多个构造步骤)来生成不同类型的对象。
图5:不同生成器以不同的方式执行相同的任务

图5:不同生成器以不同的方式执行相同的任务[/caption]
  例如,假设第一个建造者使用木头和玻璃制造房屋,第二个建造者使用石头和钢铁,而第三个建造者使用黄金和钻石。在调用同一组步骤后,第一个建造者会给你一栋普通房屋,第二个会给你一座小城堡,而第三个则会给你一座宫殿。但是,只有在调用构造步骤的客户端代码可以通过通用接口与建造者进行交互时,这样的调用才能返回需要的房屋。

3.2 主管

  你可以进一步将用于创建产品的一系列生成器步骤调用抽取成为单独的主管类。主管类可定义创建步骤的执行顺序,而生成器则提供这些步骤的实现。

图6:主管知道需要哪些创建步骤才能获得可正常使用的产品

图6:主管知道需要哪些创建步骤才能获得可正常使用的产品[/caption]
  严格来说,你的程序中并不一定需要主管类。客户端代码可直接以特定顺序调用创建步骤。不过,主管类中非常适合放入各种例行构造流程,以便在程序中反复使用。此外,对于客户端代码来说,主管类完全隐藏了产品构造细节。客户端只需要将一个生成器与主管类关联,然后使用主管类来构造产品,就能从生成器处获得构造结果了。
  主管只负责生成的步骤,完成后仍然从生成器中获得产品

四、UML

图7:生成器结构

五、实例

  下面我们来修个房屋,做一个简单的演示。

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

// 产品(房屋): 通过Builder装配后生产的零件
class House
{
public:
    // 存放具体产品的parts
    std::vector<std::string> m_parts;

    void showPartsList()
    {
        for (auto i : m_parts)
        {
            std::cout << i << ' ';
        }
        std::cout << std::endl;
    }
};

class Builder
{
public:
    virtual ~Builder() {}

    virtual void ProducePartA() const = 0;

    virtual void ProducePartB() const = 0;

    virtual void ProducePartC() const = 0;
};

class HouseBuilder : public Builder
{
private:
    House* m_house;
public:
    HouseBuilder() : Builder()
    {
        this->Reset();
        // 新创建的Builder的产品必须是空的
    }

    ~HouseBuilder()
    {
        delete m_house;
    }

    // 重设产品
    void Reset()
    {
        this->m_house = new House();
    }

    void ProducePartA() const override
    {
        this->m_house->m_parts.push_back("Door");
    }

    void ProducePartB() const override
    {
        this->m_house->m_parts.push_back("Floor");
    }

    void ProducePartC() const override
    {
        this->m_house->m_parts.push_back("Walls");
    }

    // 获得产品
    House* getHouse()
    {
        House* re = this->m_house;
        this->Reset();
        return re;
    }
};

// 主管
class Director
{
private:
    Builder* m_Builder;
public:
    // 主管可以使用任意的Builder,但需要客户端指定
    void setBuilder(Builder* p_Builder)
    {
        this->m_Builder = p_Builder;
    }

    void BuildNormalHouse()
    {
        this->m_Builder->ProducePartA();
        this->m_Builder->ProducePartB();
        this->m_Builder->ProducePartC();
    }

    void BuildAbnormalHouse()
    {
        this->m_Builder->ProducePartB();
    }
};

// 客户端代码
void Client(Director& p_director)
{
    /* ===== Section 0 : 生产一个正常的房屋 ===== */
    std::cout << "Build A Normal House" << std::endl;

    // 给主管指定生成器
    HouseBuilder* houseBuilder = new HouseBuilder();
    p_director.setBuilder(houseBuilder);

    // 主管生产后取回产品
    p_director.BuildNormalHouse();
    House* normalHouse = houseBuilder->getHouse();

    normalHouse->showPartsList();
    delete normalHouse;

    /* ===== Section 1 : 生产一个不正常的房屋 ===== */
    std::cout << "Build An Abnormal House" << std::endl;

    // 主管生产后取回产品
    p_director.BuildAbnormalHouse();
    House* abnormalHouse = houseBuilder->getHouse();

    abnormalHouse->showPartsList();
    delete abnormalHouse;

    delete houseBuilder;
    return;
}

int main()
{
    Director* director = new Director();
    Client(*director);

    delete director;
    return 0;
}
退出移动版