【设计模式】建造者模式(Builder)

目录

一、问题导入

二、结构(如果只是应付考试的话,可以不细看)

三、优劣

四、另一种形式

五、个人理解


一、问题导入

我们点一个汉堡,商家按固定搭配做好,我们直接拿成品,这是工厂方法 ------ 没法选肉饼、配菜,只能接受预设方案。但如果我们自己一步一步选、一步一步组合:要牛肉饼、加生菜、抹番茄酱,最后拼成汉堡,这就是建造者模式

从中能看出,工厂方法 是一步拿结果,建造者模式 是多步定制、最后得结果。接下来,我们进一步探讨建造者模式

二、结构(如果只是应付考试的话,可以不细看)

接着从上述案例出发,我们首先需要定义一个产品类hambuger 。之后,提供一个抽象生成器hamburger_builder 用来生成汉堡。然后,还可以提供具体生成器 ,用以生成固定的产品,比如用以生成安格斯牛堡的beef_hambuger_builder,让他提供固定的流程。最后,只需要再去提供一个导演类director去指导builder来生成想要的产品。

那么,他的整体结构如下:

下面,给出了相应的示例代码:

在进行使用的过程中,我们可以通过director类来获取预定好的组成部分(个人认为该种形式无法很明显地体现建造者模式工厂模式的区别)

也可以通过直接使用CustomerBurgerBuilder来进行自定义汉堡内容

cpp 复制代码
#pragma once
#include <iostream>
#include <string>

// 命名空间:与你的_AbstractFactory风格保持一致
namespace _BuilderPattern
{
    // 1. 产品:汉堡(最终要构建的复杂对象)
    class Burger
    {
    private:
        std::string patty_;    // 肉饼(成员变量用_结尾)
        std::string vegetable_;// 蔬菜
        std::string sauce_;    // 酱料

    public:
        // 构造与析构(默认实现)
        Burger() = default;
        ~Burger() = default;

        // 设置汉堡各部分(接口函数)
        void setPatty(const std::string& patty) { patty_ = patty; }
        void setVegetable(const std::string& vegetable) { vegetable_ = vegetable; }
        void setSauce(const std::string& sauce) { sauce_ = sauce; }

        // 展示汉堡组成(功能函数)
        void show() const
        {
            std::cout << "汉堡组成:" << patty_ << " + " << vegetable_ << " + " << sauce_ << std::endl;
        }
    };

    // 2. 抽象建造者:定义汉堡构建的步骤接口
    class BurgerBuilder
    {
    public:
        BurgerBuilder() = default;
        virtual ~BurgerBuilder() = default; // 虚析构,确保子类正确释放

        // 纯虚函数:分步构建(参数化,支持自定义)
        virtual void buildPatty(const std::string& patty) = 0;
        virtual void buildVegetable(const std::string& vegetable) = 0;
        virtual void buildSauce(const std::string& sauce) = 0;

        // 获取最终产品
        virtual Burger* getResult() = 0;
    };

    // 3. 具体建造者:实现汉堡的构建逻辑
    class CustomBurgerBuilder : public BurgerBuilder
    {
    private:
        Burger* burger_; // 持有当前构建的汉堡对象

    public:
        CustomBurgerBuilder()
        {
            burger_ = new Burger(); // 初始化空汉堡
        }

        ~CustomBurgerBuilder() override
        {
            delete burger_; // 释放资源
        }

        // 实现抽象方法:设置具体配料
        void buildPatty(const std::string& patty) override
        {
            burger_->setPatty(patty);
        }

        void buildVegetable(const std::string& vegetable) override
        {
            burger_->setVegetable(vegetable);
        }

        void buildSauce(const std::string& sauce) override
        {
            burger_->setSauce(sauce);
        }

        // 返回构建完成的汉堡
        Burger* getResult() override
        {
            return burger_;
        }
    };

    // 4. 导演:封装预设构建流程(可选,简化常用组合)
    class Director
    {
    private:
        BurgerBuilder* builder_; // 依赖抽象建造者(多态)

    public:
        // 传入具体建造者
        Director(BurgerBuilder* builder) : builder_(builder) {}
        ~Director() = default;

        // 预设方案1:经典牛肉汉堡
        void buildClassicBeefBurger()
        {
            builder_->buildPatty("炭烤牛肉饼");
            builder_->buildVegetable("生菜+番茄片");
            builder_->buildSauce("番茄酱+芥末酱");
        }

        // 预设方案2:招牌鸡肉汉堡
        void buildSignatureChickenBurger()
        {
            builder_->buildPatty("香煎鸡胸肉");
            builder_->buildVegetable("黄瓜丝+洋葱圈");
            builder_->buildSauce("蜂蜜沙拉酱");
        }
    };

    // 测试函数:验证模式功能(与你的test()风格一致)
    void test()
    {
        std::cout << "=== 建造者模式(汉堡案例)测试 ===" << std::endl;

        // 场景1:用导演快速制作预设汉堡
        CustomBurgerBuilder classicBuilder;
        Director director(&classicBuilder);
        director.buildClassicBeefBurger(); // 调用预设流程
        Burger* classicBurger = classicBuilder.getResult();
        std::cout << "【经典牛肉堡】" << std::endl;
        classicBurger->show();

        // 场景2:完全自定义汉堡(体现建造者的核心价值)
        CustomBurgerBuilder myBuilder;
        myBuilder.buildPatty("双层植物肉");    // 自定义肉饼
        myBuilder.buildVegetable("牛油果+紫甘蓝"); // 自定义蔬菜
        myBuilder.buildSauce("蒜香蛋黄酱");    // 自定义酱料
        Burger* myBurger = myBuilder.getResult();
        std::cout << "\n【自定义植物汉堡】" << std::endl;
        myBurger->show();
    }
}

三、优劣

优势:

(1)分离构建过程和表示形式,使构建过程更具灵活性,并允许构建不同的表示形式

(比如做汉堡时,"选配料的过程" 和 "最终汉堡的样子" 是分离的,既可以做经典牛肉堡,也可以自定义植物汉堡,灵活性很高。)

(2)可以更好地控制构建过程,并隐藏具体的构建细节

(用户只需要关心 "选什么配料",不需要知道汉堡是怎么组装的(比如面包怎么夹、酱料怎么涂),细节被隐藏了。)

(3)代码可复用性高,同一个构建器可在不同的构建流程中复用

(同一个 CustomBurgerBuilder 既可以给导演用来做预设汉堡,也可以自己用来做自定义汉堡,不用重复写逻辑。)

劣势:

(1)若产品的属性较少,建造者模式可能会导致代码冗余。

如果汉堡只有 "肉饼" 一个属性,用建造者模式就没必要,直接一个工厂方法更简单。

(2)建造者模式会增加系统中类和对象的数量。

产品、抽象建造者、具体建造者、导演,类的数量比简单工厂多,小项目可能觉得 "重"。

四、另一种形式

建造者模式还有另一种表达形式,那就是在构造函数当中提供所有的预设值,而在其每一个设置属性的函数当中,其设置返回值为当前对象自身(this),从而在进行对象的实例化的时候,通过链式调用来进行初始化。

不过,这种写法将会导致类的构造函数十分冗杂,我个人并不喜欢这种表达形式。

五、个人理解

建造者模式 实际上也是一种创建对象的方式,就工厂模式而言,我们可以获得一个固定的产品。但是,当产品的属性变得多样且不可控的时候,他们的整体制作流程往往不需要改变,那么,用户就只需要考虑单个组件如何进行选择即可。

就比如常见的换装游戏,我们自然可以预先设定好几套风格的衣服供玩家自行选择(古风还是现代风的)。但是,往往我们也需要"打开衣橱",让玩家自行一一挑选。不过,不管我们先选头发还是先选帽子,其渲染的结果始终是先进行头发的渲染,后进行帽子的渲染,从而确保帽子覆盖在头发上面,这便是固化的流程,其对于用户来说是看不到的。(这是我能够想到的一个比较典型且契合的应用。)

相关推荐
筏.k7 小时前
C++ 设计模式系列:生产者-消费者模式完全指南
开发语言·c++·设计模式
Tiny_React19 小时前
智能体设计模式-附录 C - 智能体框架快速概览
设计模式
YBN娜1 天前
设计模式-创建型设计模式
java·开发语言·设计模式
YuanlongWang1 天前
C# 设计模式——单例模式
单例模式·设计模式·c#
Code_Geo1 天前
agent设计模式:第二章节—路由
网络·设计模式·路由
太过平凡的小蚂蚁1 天前
解耦的艺术:深入理解设计模式之命令模式
设计模式·命令模式
Meteors.1 天前
23种设计模式——外观模式(Facade Pattern)详解
设计模式·外观模式
胖虎11 天前
iOS中的设计模式(九)- 外观模式 用外观模式点一份外卖:Swift 实战讲解
设计模式·外观模式
Asort1 天前
JavaScript设计模式(十六)——迭代器模式:优雅遍历数据的艺术
前端·javascript·设计模式