当前位置: 首页 > news >正文

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

目录

一、问题导入

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

三、优劣

四、另一种形式

五、个人理解


一、问题导入

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

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

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

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

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

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

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

#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),从而在进行对象的实例化的时候,通过链式调用来进行初始化。

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

五、个人理解

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

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

http://www.dtcms.com/a/511481.html

相关文章:

  • DeepSeek-OCR:把长文本“挤进图片”的新思路
  • 计算机做网站开题报告网页的六个基本元素
  • AI服务器工作之整机部件(CPU+内存)
  • 【EE初阶 - 网络原理】网络层 + 数据链路层 + DNS
  • 关于二级网站建设西安网站制作一般多少钱
  • 【机器学习06】神经网络的实现、训练与向量化
  • [人工智能-大模型-25]:大模型应用层技术栈 - 大模型应用层的四大开发模式(如何利用大语言模型?)
  • YOLO目标检测:一种用于无人机的新型轻量级目标检测网络
  • 第六部分:VTK进阶(第166章 标量-向量-张量场管理)
  • A Survey of Camouflaged Object Detection and Beyond论文阅读笔记
  • 基于 hexo + github 的个人博客系统搭建
  • 成都私人做网站建设自由做图网站
  • 哈尔滨做网站找哪家好网站的在线支付怎么做
  • 使用pem和key文件给springboot开启https服务
  • XSS攻击防护完整指南
  • 基于Spring Boot的高校实习实践管理系统(源码+论文+部署+安装)
  • 第11篇:源码解析:Jackson核心流程与设计模式
  • 数据库原理实验报告:在ider里搭建mysql数据库
  • 面试(四)——Java 八大包装类、String 、日期类及文件操作核心类 File全解析
  • 【无标题】大模型-7种大模型微调方法 上
  • 信用网站系统建设方案阿里云服务器建设网站选择那个镜像
  • 大型的PC网站适合vue做吗网页制作工具通常在什么上建立热点
  • C++字符串操作与递增递减运算符详解
  • Python 的基本数据类型与它们之间的关系
  • All in One Runtimes下载和安装图解(附安装包,适合新手)
  • Python多patch装饰器使用指南
  • Prometheus监控系统
  • 【Java-集合】Set接口
  • 安卓开发- Log日志工具类
  • 微信链接的微网站怎么做的wordpress注册邮件设置密码