构建器模式 Builder

“对象创建”模式

  • 通过“对象创建” 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定。它是接口抽象之后的第一步工作。
  • 典型模式
  1. Factory Method
  2. Abstract Factory
  3. Prototype
  4. Builder

这个模式用的比较少。比较像模板方法模式。

动机(Motivation)

  • 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
  • 如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?

C++ 中构造函数你调用虚函数是静态绑定。因为派生类的构造函数先调用基类的构造函数。

模式定义

将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。 ——《设计模式》GoF

代码示例

#include <iostream>
using namespace std;

class House
{
public:
    void Init()
    {
        BuildPart1();
        // 建四个窗
        for (int i = 0; i < 4; i++) {
            BuildPart2();
        }
        bool flag = BuildPart3();
        if (flag) {
            BuildPart4();
        }
        BuildPart5();
    }
    virtual ~House(){}

protected:
    virtual void BuildPart1() = 0;
    virtual void BuildPart2() = 0;
    virtual bool BuildPart3() = 0;
    virtual void BuildPart4() = 0;
    virtual void BuildPart5() = 0;
};

class StoneHouse: public House
{
protected:
    virtual void BuildPart1()
    {
        cout << "part" << 1 << endl;
    }
    virtual void BuildPart2()
    {
        cout << "part" << 2 << endl;
    }
    virtual bool BuildPart3()
    {
        cout << "part" << 3 << endl;
        return true;
    }
    virtual void BuildPart4()
    {
        cout << "part" << 4 << endl;
    }
    virtual void BuildPart5()
    {
        cout << "part" << 5 << endl;
    }
};

int main()
{
    House *pHouse = new StoneHouse;
    pHouse->Init(); // 完成构建。  C++ 中构造函数里面的虚函数调用是静态绑定的,所以这里用 Init 函数。

    getchar();
    return 0;
}

输出:

part1
part2
part2
part2
part2
part3
part4
part5

修改版,根据自己理解写的,不太确定是不是这个意思:

#include <iostream>
#include <string>
using namespace std;

// 抽象基类
class House {
public:
    void showInfo()
    {
        cout << one << two << three << four << five << endl;
    }
    virtual void Do() = 0;
protected:
    string one;
    string two;
    string three;
    string four;
    string five;
};

// 抽象基类
class HouseBuilder {
public:
    House* GetResult() {
        return pHouse;
    }
    virtual ~HouseBuilder() {}
    HouseBuilder(House *house) :pHouse(house)
    {
    }
protected:
    House* pHouse;
public:
    virtual void BuildPart1() = 0;
    virtual void BuildPart2() = 0;
    virtual bool BuildPart3() = 0;
    virtual void BuildPart4() = 0;
    virtual void BuildPart5() = 0;
};

class StoneHouse : public House {
public:
    virtual void Do()
    {
        cout << "石头房:";
        showInfo();
    }
    friend class StoneHouseBuilder;
};

class StoneHouseBuilder : public HouseBuilder {
public:
    StoneHouseBuilder(House *house) :HouseBuilder(house) {}
protected:
    virtual void BuildPart1() {
        StoneHouse* p = static_cast<StoneHouse*>(pHouse); // 友元不能继承?
        p->one = "一座屋,";
    }
    virtual void BuildPart2() {
        StoneHouse* p = static_cast<StoneHouse*>(pHouse);
        p->two += "两间房,";
    }
    virtual bool BuildPart3() {
        StoneHouse* p = static_cast<StoneHouse*>(pHouse);
        p->three = "三扇门,";
        return true;
    }
    virtual void BuildPart4() {
        StoneHouse* p = static_cast<StoneHouse*>(pHouse);
        p->four = "四个窗,";
    }
    virtual void BuildPart5() {
        StoneHouse* p = static_cast<StoneHouse*>(pHouse);
        p->five = "五张桌。";
    }
};

class HouseDirector {
    HouseBuilder* pHouseBuilder;
public:
    HouseDirector(HouseBuilder* pHouseBuilder) {
        this->pHouseBuilder = pHouseBuilder;
    }

    House* Construct()
    {
        pHouseBuilder->BuildPart1();
        for (int i = 0; i < 4; i++) {
            pHouseBuilder->BuildPart2();
        }
        bool flag = pHouseBuilder->BuildPart3();
        if (flag) {
            pHouseBuilder->BuildPart4();
        }
        pHouseBuilder->BuildPart5();

        return pHouseBuilder->GetResult();
    }
};


int main()
{
    StoneHouse stoneHouse;
    StoneHouseBuilder stoneHouseBuilder(&stoneHouse);
    HouseDirector houseDirector(&stoneHouseBuilder);

    House* myHouse = houseDirector.Construct();
    myHouse->Do();

    getchar();
    return 0;
}

输出:

石头房:一座屋,两间房,两间房,两间房,两间房,三扇门,四个窗,五张桌。

类图

要点总结

  • Builder 模式主要用于“分步骤构建一个复杂的对象”。在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
  • 变化点在哪里,封装哪里—— Builder模式主要在于应对“复杂对象各个部分”的频繁需求变动。其缺点在于难以应对“分步骤构建算法”的需求变动。
  • 在Builder模式中,要注意不同语言中构造器内调用虚函数的差别(C++ vs. C#) 。




参考:GeekBand

posted @   double64  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-09-27 C# 接口类型
2021-09-27 C# 小数位控制
2021-09-27 C# 自定义鼠标样式 1
2021-09-27 C# 自定义鼠标样式
2021-09-27 C# 委托和事件的区别
2021-09-27 简单测试下 goto 语句
2021-09-27 配置 OpenCV 开发环境
点击右上角即可分享
微信分享提示