c++注意点(12)----设计模式(生成器)

创建型模式

        生成器模式(Builder Pattern)是一种创建型设计模式,它专注于将复杂对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。

        就像是做饭,你可以自己慢慢做,各个步骤自己选择。而使用生成器就像是预制菜,所有的最后菜的样子,已经规划好了。你只能从中选择一个。

为什么需要生成器模式?

        当我们需要创建具有复杂内部结构的对象(比如包含多个部件、构建步骤繁琐或有多种配置方式的对象)时,直接在构造函数中处理会导致:

  • 构造函数参数过多,难以维护(比如创建一个 "电脑" 对象,需要指定 CPU、内存、硬盘、显卡等十几种参数);
  • 不同配置的对象需要不同的构建逻辑,导致代码臃肿;
  • 构建过程与对象表示耦合,无法灵活切换不同的构建方式

举个生活中的例子

想象你去电脑店组装一台电脑,整个过程其实很复杂:

  1. 需要选很多零件(CPU、内存、硬盘、显卡等);
  2. 零件之间有搭配要求(比如主板要兼容 CPU);
  3. 组装有固定步骤(先装主板,再插 CPU,最后装机箱);
  4. 不同需求选的零件不同(办公用不需要好显卡,游戏用需要大内存)。

如果没有生成器模式,就像你自己去买零件、自己组装:

  • 要记住所有零件型号和搭配规则,很容易出错;
  • 每次换配置(比如从办公电脑换成游戏电脑),都要重新学一遍选零件和组装的流程;
  • 步骤错了(比如先装显卡再装主板),可能装不上。

生成器模式就像请了一个专业装机师傅(生成器)和一个客户经理(指挥者):

  • 你只需要告诉客户经理 “我要一台办公电脑”,不用管具体零件和步骤;
  • 装机师傅知道所有零件搭配规则和组装顺序,会按步骤一步步装好;
  • 想换游戏电脑?换一个擅长装游戏电脑的师傅(另一个生成器)就行,你不用学新东西。

示例

#include <iostream>
#include <string>// 最终产品:电脑
class Computer {
private:std::string cpu_;       // 处理器std::string memory_;    // 内存std::string hardDisk_;  // 硬盘std::string graphics_;  // 显卡std::string power_;     // 电源public:// 设置各部件(让生成器可以修改内部属性)void setCPU(const std::string& cpu) { cpu_ = cpu; }void setMemory(const std::string& memory) { memory_ = memory; }void setHardDisk(const std::string& hardDisk) { hardDisk_ = hardDisk; }void setGraphics(const std::string& graphics) { graphics_ = graphics; }void setPower(const std::string& power) { power_ = power; }// 获取各部件信息std::string getCPU() const { return cpu_; }std::string getMemory() const { return memory_; }std::string getHardDisk() const { return hardDisk_; }std::string getGraphics() const { return graphics_; }std::string getPower() const { return power_; }// 显示电脑配置void showConfig() const {std::cout << "电脑配置:\n";std::cout << "CPU:" << cpu_ << "\n";std::cout << "内存:" << memory_ << "\n";std::cout << "硬盘:" << hardDisk_ << "\n";std::cout << "显卡:" << graphics_ << "\n";std::cout << "电源:" << power_ << "\n\n";}
};// 生成器接口(抽象类):定义组装步骤
class Builder {
protected:Computer computer_;  // 正在组装的电脑public:// 纯虚函数:组装各部件的步骤virtual void buildCPU() = 0;virtual void buildMemory() = 0;virtual void buildHardDisk() = 0;virtual void buildGraphics() = 0;virtual void buildPower() = 0;// 返回组装好的电脑virtual Computer getComputer() {return computer_;}// 虚析构函数virtual ~Builder() = default;
};// 具体生成器1:办公电脑生成器
class OfficeBuilder : public Builder {
public:void buildCPU() override {computer_.setCPU("英特尔 i5(入门级)");std::cout << "安装办公电脑CPU:" << computer_.getCPU() << "\n";}void buildMemory() override {computer_.setMemory("8G DDR4");std::cout << "安装办公电脑内存:" << computer_.getMemory() << "\n";}void buildHardDisk() override {computer_.setHardDisk("512G 固态硬盘");std::cout << "安装办公电脑硬盘:" << computer_.getHardDisk() << "\n";}void buildGraphics() override {computer_.setGraphics("集成显卡");std::cout << "安装办公电脑显卡:" << computer_.getGraphics() << "\n";}void buildPower() override {computer_.setPower("300W 电源");std::cout << "安装办公电脑电源:" << computer_.getPower() << "\n";}
};// 具体生成器2:游戏电脑生成器
class GameBuilder : public Builder {
public:void buildCPU() override {computer_.setCPU("英特尔 i7(高性能)");std::cout << "安装游戏电脑CPU:" << computer_.getCPU() << "\n";}void buildMemory() override {computer_.setMemory("16G DDR5");std::cout << "安装游戏电脑内存:" << computer_.getMemory() << "\n";}void buildHardDisk() override {computer_.setHardDisk("1T 固态硬盘");std::cout << "安装游戏电脑硬盘:" << computer_.getHardDisk() << "\n";}void buildGraphics() override {computer_.setGraphics("RTX 4060 独立显卡");std::cout << "安装游戏电脑显卡:" << computer_.getGraphics() << "\n";}void buildPower() override {computer_.setPower("500W 电源");std::cout << "安装游戏电脑电源:" << computer_.getPower() << "\n";}
};// 指挥者:负责控制组装流程
class Director {
private:Builder* builder_;  // 指向当前使用的生成器public:// 构造函数:传入生成器Director(Builder* builder) : builder_(builder) {}// 指挥组装电脑(固定步骤)Computer construct() {std::cout << "开始组装电脑...\n";builder_->buildCPU();builder_->buildMemory();builder_->buildHardDisk();builder_->buildGraphics();builder_->buildPower();std::cout << "组装完成!\n\n";return builder_->getComputer();}
};// 客户端:用户购买电脑
int main() {// 1. 准备生成器(装机师傅)OfficeBuilder officeBuilder;  // 办公电脑装机师傅GameBuilder gameBuilder;      // 游戏电脑装机师傅// 2. 准备指挥者(客户经理)Director director(nullptr);// 3. 组装办公电脑std::cout << "=== 组装办公电脑 ===\n";director = Director(&officeBuilder);  // 安排办公装机师傅Computer officeComputer = director.construct();  // 开始组装officeComputer.showConfig();  // 查看配置// 4. 组装游戏电脑std::cout << "=== 组装游戏电脑 ===\n";director = Director(&gameBuilder);  // 换游戏装机师傅Computer gameComputer = director.construct();  // 开始组装gameComputer.showConfig();  // 查看配置return 0;
}

        当然。有些参数是不一定使用的,可以选择使用哪些。那么这里给出第二个示例,用于参考,额外的参数配置部分。

#include <iostream>
#include <string>
#include <vector>// 电脑产品(支持可选配件)
class Computer {
private:std::string cpu_;        // 必选:CPUstd::string memory_;     // 必选:内存std::string hardDisk_;   // 必选:硬盘std::string graphics_;   // 可选:显卡(核显/独显)std::string power_;      // 必选:电源std::vector<std::string> extras_; // 可选:额外配件(如散热器、蓝牙模块)public:// 设置必选部件void setCPU(const std::string& cpu) { cpu_ = cpu; }void setMemory(const std::string& memory) { memory_ = memory; }void setHardDisk(const std::string& hardDisk) { hardDisk_ = hardDisk; }void setPower(const std::string& power) { power_ = power; }// 设置可选部件void setGraphics(const std::string& graphics) { graphics_ = graphics; }void addExtra(const std::string& extra) { extras_.push_back(extra); }// 获取部件信息(用于生成器输出)std::string getCPU() const { return cpu_; }std::string getMemory() const { return memory_; }std::string getHardDisk() const { return hardDisk_; }std::string getGraphics() const { return graphics_; }std::string getPower() const { return power_; }// 显示配置(区分必选和可选)void showConfig() const {std::cout << "===== 电脑配置 =====" << "\n";std::cout << "【必选部件】\n";std::cout << "CPU:" << cpu_ << "\n";std::cout << "内存:" << memory_ << "\n";std::cout << "硬盘:" << hardDisk_ << "\n";std::cout << "电源:" << power_ << "\n";std::cout << "\n【可选部件】\n";std::cout << "显卡:" << (graphics_.empty() ? "无(使用核显)" : graphics_) << "\n";std::cout << "额外配件:";if (extras_.empty()) {std::cout << "无";}else {for (const auto& extra : extras_) {std::cout << extra << "、";}}std::cout << "\n====================\n\n";}
};// 生成器接口(支持可选步骤)
class Builder {
protected:Computer computer_;public:// 必选步骤(纯虚函数,必须实现)virtual void buildCPU() = 0;virtual void buildMemory() = 0;virtual void buildHardDisk() = 0;virtual void buildPower() = 0;// 可选步骤(虚函数,默认空实现,可选择性重写)virtual void buildGraphics() {}  // 可选:装独立显卡virtual void addExtra(const std::string& extra) {  // 可选:加配件computer_.addExtra(extra);}virtual Computer getComputer() { return computer_; }virtual ~Builder() = default;
};// 具体生成器1:极简办公电脑(不选独显,不加额外配件)
class MinimalOfficeBuilder : public Builder {
public:void buildCPU() override {computer_.setCPU("英特尔 i3(低功耗)");std::cout << "安装CPU:" << computer_.getCPU() << "\n";}void buildMemory() override {computer_.setMemory("4G DDR4");std::cout << "安装内存:" << computer_.getMemory() << "\n";}void buildHardDisk() override {computer_.setHardDisk("256G 固态硬盘");std::cout << "安装硬盘:" << computer_.getHardDisk() << "\n";}void buildPower() override {computer_.setPower("200W 电源");std::cout << "安装电源:" << computer_.getPower() << "\n";}// 不重写buildGraphics(),使用默认空实现(不装独显)// 不调用addExtra(),所以无额外配件
};// 具体生成器2:高端游戏电脑(选独显,加多个配件)
class HighEndGameBuilder : public Builder {
public:void buildCPU() override {computer_.setCPU("AMD Ryzen 9(旗舰级)");std::cout << "安装CPU:" << computer_.getCPU() << "\n";}void buildMemory() override {computer_.setMemory("32G DDR5");std::cout << "安装内存:" << computer_.getMemory() << "\n";}void buildHardDisk() override {computer_.setHardDisk("2T 固态硬盘");std::cout << "安装硬盘:" << computer_.getHardDisk() << "\n";}void buildPower() override {computer_.setPower("800W 金牌电源");std::cout << "安装电源:" << computer_.getPower() << "\n";}// 重写可选步骤:安装独显void buildGraphics() override {computer_.setGraphics("RTX 4090 独显");std::cout << "安装显卡:" << computer_.getGraphics() << "\n";}
};// 指挥者(支持灵活调整步骤)
class Director {
private:Builder* builder_;public:Director(Builder* builder) : builder_(builder) {}// 基础组装(只包含必选步骤)Computer buildBasic() {std::cout << "=== 开始基础组装(必选部件)===\n";builder_->buildCPU();builder_->buildMemory();builder_->buildHardDisk();builder_->buildPower();std::cout << "基础组装完成!\n";return builder_->getComputer();}// 完整组装(必选+可选步骤)Computer buildComplete() {std::cout << "\n=== 开始完整组装(必选+可选)===\n";Computer basic = buildBasic();  // 复用基础组装逻辑builder_->buildGraphics();      // 可选:装显卡builder_->addExtra("水冷散热器"); // 可选:加配件builder_->addExtra("蓝牙模块");   // 可选:加配件std::cout << "完整组装完成!\n";return builder_->getComputer();}
};// 客户端:灵活定制不同配置
int main() {// 1. 组装极简办公电脑(只装必选部件)MinimalOfficeBuilder officeBuilder;Director officeDirector(&officeBuilder);Computer officePC = officeDirector.buildBasic();  // 只调用必选步骤officePC.showConfig();// 2. 组装高端游戏电脑(必选+可选部件)HighEndGameBuilder gameBuilder;Director gameDirector(&gameBuilder);Computer gamePC = gameDirector.buildComplete();  // 调用必选+可选步骤gamePC.showConfig();// 3. 临时加配件(生成器模式支持中途调整)std::cout << "给办公电脑临时加一个配件:\n";officeBuilder.addExtra("无线网卡");officePC = officeBuilder.getComputer();officePC.showConfig();return 0;
}

优势

        1.使用生成器模式可避免 “重叠构造函数 (telescoping constructor)” 的出现。

         假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便; 因此, 你需要重载这个构造函数, 新建几个只有较少参数的简化版。 但这些构造函数仍需调用主构造函数, 传递一些默认数值来替代省略掉的参数。

class Pizza {Pizza(int size) { …… }Pizza(int size, boolean cheese) { …… }Pizza(int size, boolean cheese, boolean pepperoni) { …… }
//............

        生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/90465.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/90465.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[特殊字符] VLA 如何“绕过”手眼标定?—— 当机器人学会了“看一眼就动手”

&#x1f52e; VLA 如何“绕过”手眼标定&#xff1f;—— 当机器人学会了“看一眼就动手” 作者&#xff1a;石去皿 发布时间&#xff1a;2025年7月 在传统机器人系统中&#xff0c;“手眼标定”是每一个工程师都绕不开的课题。 你必须精确测量相机和机械臂之间的空间变换关系…

《Maven 核心基础笔记(第一天)》

1.说明maven软件依赖管理和项目构建功能maven是为Java项目工作的 功能体现&#xff1a;依赖管理&#xff0c;项目构建 依赖管理&#xff1a;我们只需要写配置文件(pom.xml)&#xff0c;maven就会帮我们下载依赖&#xff0c;并且也会下载依赖的依赖。 项目构建&#xff1a;项目源…

Yolo底层原理学习(V1~V3)(第一篇)

一&#xff0c;卷积后的特征图大小计算众所周知&#xff0c;提到深度学习&#xff0c;必不可少的会提及卷积&#xff0c;那么如何计算卷积之后的图片大小呢&#xff1f;下图呈现&#xff1a;如图&#xff0c; 我们令FH&#xff0c;FW为原图像的长度FH*FW。P为padding的长度&…

前端开发项目性能瓶颈分析

1. 使用 rollup-plugin-visualizer 分析构建 借助 rollup-plugin-visualizer 插件&#xff0c;可以分析通过 rollup 构建出的产物内容&#xff0c;并生成可视化图表&#xff0c;帮助你分析打包后的文件大小以及各个模块的占用情况。 1.1. 安装插件 你需要在你的项目中安装 r…

ExoData.h - OpenExo

ExoData.h文件定位源代码1. 头文件依赖2. 核心类声明3. 主要成员函数关节遍历工具关节与配置相关数据/状态操作控制参数/校准4. 主要成员变量总结文件定位 位置&#xff1a;src/ExoData.h 作用&#xff1a;定义 ExoData 类&#xff0c;作为 Exo 系统全局数据的核心容器。它将设…

缓存HDC内容用于后续Direct2D绘制.

思路&#xff1a;把HDC里的内容保存到Direct2D格式的位图里&#xff0c;后续直接调用 renderTarget->DrawBitmap即可。本例中&#xff0c;位图将保存为类的字段。本例中 COM 接口指针皆使用 com_ptr&#xff0c;这是 WinRT 的 COM 智能指针类&#xff0c;com_ptr<I>::…

“抓了个寂寞”:一次实时信息采集的意外和修复

1. 那天下午&#xff0c;舆情系统“迟到”了 那天下午&#xff0c;公司运营那边突然在群里喊&#xff1a;“XX事件都快上热搜榜前十了&#xff0c;咱们系统咋没反应&#xff1f;” 我愣了几秒&#xff0c;立马翻后台日志、爬虫执行记录&#xff0c;结果一查&#xff0c;还真有点…

数据结构之迪杰斯特拉算法

前言&#xff1a;前面两篇文章介绍了生成图的最小生成树的算法&#xff0c;接下来两篇文章会介绍图的最短路径的算法&#xff0c;迪杰斯特拉算法和弗洛伊德算法。迪杰斯特拉算法是用来计算一个点到其他所有点的最短路径&#xff0c;这个点称之为源点。 一、实现流程 回忆一下…

技术文档 | OpenAI 的 Kafka 演进之路与 Pulsar 迁移潜力

导读ChatGPT 用户量指数级暴涨&#xff0c;OpenAI 的 Kafka 集群在一年内增长 20 倍至 30 个集群[1]&#xff0c;其 Kafka 架构面临日均千亿级消息&#xff08;峰值 QPS 800万/秒&#xff09; 的压力。这揭示了一个关键事实&#xff1a;OpenAI 的成功不只依赖模型&#xff0c;更…

【bug】 jetson上opencv无法录制h264本地视频

在Jetson Orin NX上无法使用opencv直接录制h264/h265视频流&#xff08;h264格式的视频流才能在浏览器播放&#xff09; 解决&#xff1a; 软件编码&#xff1a;需要源码编译opencv 1.环境准备 pip uninstall opencv-python sudo apt install build-essential cmake git python…

解决http的web服务中与https服务交互的问题

问题背景&#xff1a; 需要在一个http的web服务中直接跟另一个https服务交互&#xff0c;不经过自身后端。 又来到了熟悉的跨域访问问题。 解决逻辑就是使用nginx转发&#xff0c;涉及到的文件也就是nginx.conf文件&#xff0c;前面解决minio链接时已经有经验了&#xff0c;但…

网站访问信息追踪系统在安全与性能优化中的关键作用——网络安全—仙盟创梦IDE

<?php // 收集访问信息 $visitorInfo未来之窗 [timestamp > date(Y-m-d H:i:s),ip > $_SERVER[REMOTE_ADDR] ?? unknown,page > $_SERVER[REQUEST_URI] ?? unknown,method > $_SERVER[REQUEST_METHOD] ?? unknown,user_agent > $_SERVER[HTTP_USER_A…

Oracle 时间处理函数和操作符笔记

前言 写sql时经常用到时间处理函数&#xff0c;我整理了一份Oracle的常用sql笔记,供大家参考。 如果对你有帮助&#xff0c;请点赞支持~ 多谢&#x1f64f; 笔记 -- 1. 获取当前日期和时间 -- SYSDATE, SYSTIMESTAMP, CURRENT_DATE, CURRENT_TIMESTAMP, LOCALTIMESTAMP SELE…

TDengine时序数据库 详解

1. TDengine 简介 TDengine 是一款 高性能、分布式、支持 SQL 的时序数据库&#xff08;Time-Series Database, TSDB&#xff09;&#xff0c;专为 物联网&#xff08;IoT&#xff09;、工业互联网、金融监控、日志分析 等场景设计。其核心特点包括&#xff1a; 超高性能&…

【IDEA】idea怎么修改注册的用户名称?

文章目录[toc]问题**方法 1&#xff1a;通过 JetBrains 账户网站修改****方法 2&#xff1a;通过 IDEA 内跳转修改&#xff08;快捷方式&#xff09;****注意事项****补充&#xff1a;修改 IDEA 内的项目级用户名**如何退出IDEA用户登录&#xff1f;问题 在 IntelliJ IDEA 中修…

AR眼镜重塑外科手术导航:精准“透视”新突破

在现代医学领域&#xff0c;增强现实&#xff08;AR www.teamhelper.cn &#xff09;技术正以前所未有的方式改变外科手术导航的面貌。通过为医生提供实时的三维可视化、精准的空间定位和智能交互功能&#xff0c;AR眼镜正在成为手术室中的重要工具。本文将系统介绍AR眼镜在手术…

服务端对接 HTTP 接口传输图片 采用base64还是 multipart/form-data

在服务端对接HTTP接口传输图片时&#xff0c;选择 multipart/form-data 还是 Base64 编码&#xff0c;需要根据具体场景权衡。以下是详细对比和建议&#xff1a;1. multipart/form-data 优点 更适合大文件传输&#xff1a; 直接以二进制流传输图片&#xff0c;无需编码/解码&am…

如何在 Windows 上安装 MongoDB 及常见问题

MongoDB 是一款 NoSQL 数据库&#xff0c;在数据管理和存储方面以其无与伦比的强大功能和多功能性而脱颖而出。该平台凭借其灵活性、可扩展性和高性能保持着领先优势&#xff0c;赢得了众多企业的信赖。在这方面&#xff0c;MongoDB 以及其在 Windows 操作系统中的表现&#xf…

JS与Go:编程语言双星的碰撞与共生

在编程语言的璀璨星河中&#xff0c;JavaScript&#xff08;简称JS&#xff09;与Go语言凭借各自独特的魅力&#xff0c;成为不同领域的佼佼者。前者以灵活多变的姿态征服了前端世界&#xff0c;后者则以高效稳健的特性在后端领域崭露头角&#xff0c;二者的碰撞与共生&#xf…

【开源】WpfMap:一个基于WPF(Windows Presentation Foundation)技术构建的数据可视化大屏展示页面

文章目录一、项目概述1.1 项目定位二、适用场景2.1 企业数据展示2.2 监控中心2.3 会议展示三、功能特性3.1 高度自定义3.2 实时更新3.3 丰富的可视化组件3.4 良好的用户体验四、技术资源4.1 开源地址一、项目概述 1.1 项目定位 WpfMap是一个基于WPF&#xff08;Windows Prese…