「软件设计模式」建造者模式(Builder)

深入解析建造者模式:用C++打造灵活对象构建流水线
引言:当对象构建遇上排列组合
在开发复杂业务系统时,你是否经常面对这样的类:它有20个成员变量,其中5个是必填项,15个是可选项。当用户需要创建豪华套餐A(含加冰可乐)或基础套餐B(不要洋葱)时,传统的构造函数早已不堪重负。这正是建造者模式(Builder Pattern)大展拳脚的舞台!
一、模式精髓解析
建造者模式通过分步构建的方式解耦复杂对象的创建过程,让同一构建流程能产出不同表现形式的产品。就像麦当劳的点餐系统:选择汉堡基底→添加配料→选择饮料→完成套餐组合。
二、C++模式实现结构

核心组件拆解
- Product(产品):需要构建的复杂对象
- Builder(抽象建造者):定义构建步骤的接口
- ConcreteBuilder(具体建造者):实现具体构建逻辑
- Director(指挥者):控制构建流程(可选)
三、实战:定制汉堡套餐系统
我们以快餐店汉堡套餐系统为例,演示如何实现不同配置的套餐组合。
1. 产品类定义
#include <iostream>
#include <memory>
#include <string>
#include <vector>class HamburgerMeal {
public:void showMeal() const {std::cout << "=== 您的套餐配置 ===" << std::endl;std::cout << "主餐: " << mainItem << std::endl;std::cout << "饮料: " << drink << std::endl;std::cout << "附加项: ";for (const auto& item : sides) {std::cout << item << " ";}std::cout << "\n甜点: " << (dessert.empty() ? "无" : dessert) << std::endl;}private:friend class MealBuilder; // 允许建造者访问私有成员std::string mainItem;std::string drink;std::vector<std::string> sides;std::string dessert;
};
2. 建造者实现
class MealBuilder {
public:MealBuilder() = default;MealBuilder& setMain(const std::string& main) {meal.mainItem = main;return *this;}MealBuilder& setDrink(const std::string& drink) {meal.drink = drink;return *this;}MealBuilder& addSide(const std::string& side) {meal.sides.push_back(side);return *this;}MealBuilder& setDessert(const std::string& dessert) {meal.dessert = dessert;return *this;}HamburgerMeal build() {// 验证必要参数if (meal.mainItem.empty()) {throw std::invalid_argument("必须指定主餐");}return meal;}private:HamburgerMeal meal;
};
3. 客户端调用
#include "../../include/header.h"
#include "buger.h"
#include "meal_builder.h"
int main() {try {// 豪华套餐HamburgerMeal premiumMeal = MealBuilder().setMain("安格斯牛肉汉堡").setDrink("大杯可乐").addSide("薯条").addSide("鸡块").setDessert("苹果派").build();// 简约套餐HamburgerMeal simpleMeal = MealBuilder().setMain("经典鸡腿堡").setDrink("小杯雪碧").build();premiumMeal.showMeal();std::cout << "\n";simpleMeal.showMeal();} catch (const std::exception& e) {std::cerr << "套餐创建失败: " << e.what() << std::endl;}return 0;
}
4.执行结果

四、高级技巧:支持多种预设配置
class MealPreset {
public:static HamburgerMeal createChildrenMeal() {return MealBuilder().setMain("迷你汉堡").setDrink("牛奶").addSide("水果杯").setDessert("小饼干").build();}static HamburgerMeal createComboMeal() {return MealBuilder().setMain("双层牛肉堡").setDrink("中杯可乐").addSide("薯条").build();}
};
五、模式优势深度解析
🚀 C++实现特色优势
- 强类型检查:编译期发现类型错误
- RAII支持:自动资源管理
- 移动语义:高效的对象传递
- 灵活内存控制:支持栈对象和智能指针
💡 适用场景扩展
- 需要生成的对象有多个变体
- 对象创建需要多个步骤的初始化
- 需要隔离复杂对象的创建细节
- 需要支持不同地区配置(如语言包加载)
六、性能优化策略
- 参数预校验:在build()前进行参数检查
- 使用移动语义:减少对象拷贝开销
- 对象池技术:对频繁创建的对象进行缓存
- const正确性:确保构建后的对象不可变
七、与工厂模式对比
| 特性 | 建造者模式 | 工厂模式 |
|---|---|---|
| 构建重点 | 分步骤构建复杂对象 | 直接创建完整对象 |
| 参数处理 | 支持可选参数和分步设置 | 通常需要一次性传递所有参数 |
| 对象复杂度 | 适合构建多部件组成的复杂对象 | 适合创建单一结构的对象 |
| 扩展性 | 通过新增Builder实现不同配置 | 通过子类化工厂来创建不同对象 |
| 典型C++实现 | 链式方法+友元类 | 静态工厂方法/抽象工厂 |
八、现代C++增强实现
// 使用现代C++特性优化建造者
template<typename T>
class GenericBuilder {
protected:T object;public:operator T() && { // 右值转换运算符return std::move(object);}T build() && { // 右值build方法return std::move(object);}
};class ModernMeal : public GenericBuilder<ModernMeal> {
public:ModernMeal& setMain(std::string main) {object.mainItem = std::move(main);return *this;}// 其他设置方法类似...
};
九、最佳实践指南
- 防御性编程:在build()中进行参数合法性检查
- 清晰的接口设计:保持方法命名直观(withXxx(), addXxx())
- 不可变对象:构建完成后锁定对象状态
- 文档注释:明确每个构建步骤的作用域和约束条件
- 异常安全:确保在异常发生时资源正确释放
总结:构建的艺术
建造者模式如同一位经验丰富的建筑大师,将看似混乱的构建过程转化为标准化的装配流程。在C++的世界中,通过合理运用友元类、移动语义和模板技术,我们能够打造出既高效又灵活的对象构建系统。记住,好的设计模式应用应该像呼吸一样自然,而不是生硬的教条堆砌。
相关文章:
「软件设计模式」建造者模式(Builder)
深入解析建造者模式:用C打造灵活对象构建流水线 引言:当对象构建遇上排列组合 在开发复杂业务系统时,你是否经常面对这样的类:它有20个成员变量,其中5个是必填项,15个是可选项。当用户需要创建豪华套餐A&…...
Matlab 机器人 雅可比矩阵
工业机器人运动学与Matlab正逆解算法学习笔记(用心总结一文全会)(四)——雅可比矩阵_staubli机器人正逆向运动学实例验证matlab-CSDN博客 matlab求雅可比矩阵_六轴机械臂 矢量积法求解雅可比矩阵-CSDN博客 (63 封私信 / 80 条消息…...
DeepSeek 助力 Vue 开发:打造丝滑的面包屑导航(Breadcrumbs)
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 Deep…...
IntelliJ IDEA 2024.1.4版无Tomcat配置
IntelliJ IDEA 2024.1.4 (Ultimate Edition) 安装完成后,调试项目发现找不到Tomcat服务: 按照常规操作添加,发现服务插件中没有Tomcat。。。 解决方法 1、找到IDE设置窗口 2、点击Plugins按钮,进入插件窗口,搜索T…...
chrome://version/
浏览器输入: chrome://version/ Google浏览器版本号以及安装路径 Google Chrome131.0.6778.205 (正式版本) (64 位) (cohort: Stable) 修订版本81b36b9535e3e3b610a52df3da48cd81362ec860-refs/branch-heads/6778_155{#8}操作系统Windows…...
知识图谱数据库 Neo4j in Docker笔记
下载 docker pull neo4j:community官方说明 https://neo4j.com/docs/operations-manual/2025.01/docker/introduction/ 启动 docker run \--restart always \--publish7474:7474 --publish7687:7687 \--env NEO4J_AUTHneo4j/your_password \--volumeD:\files\knowledgegrap…...
【动手学强化学习】02多臂老虎机
问题定义 强化学习关注的是在于环境交互中学习,是一种试错学习的范式。在正式进入强化学习之前,我们先来了解多臂老虎机问题。该问题也被看作简化版的强化学习,帮助我们更快地过度到强化学习阶段。 有一个拥有 K K K 根拉杆的老虎机&#…...
【网络编程】之Udp网络通信步骤
【网络编程】之Udp网络通信步骤 TCP网络通信TCP网络通信的步骤对于服务器端对于客户端 TCP实现echo功能代码实现服务器端getsockname函数介绍 客户端效果展示 对比两组函数 TCP网络通信 TCP网络通信的步骤 对于服务器端 创建监听套接字。(调用socket函数ÿ…...
Java 基于 SpringBoot+Vue 的家政服务管理平台设计与实现
博主介绍:✌程序员徐师兄、8年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战*✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
架构——Nginx功能、职责、原理、配置示例、应用场景
以下是关于 Nginx 的功能、职责、原理、配置示例、应用场景及其高性能原因的详细说明: 一、Nginx 的核心功能 1. 静态资源服务 功能:直接返回静态文件(如 HTML、CSS、JS、图片、视频等)。配置示例:server {listen 80…...
Spring Boot中使用Flyway进行数据库迁移
文章目录 概要Spring Boot 集成 FlywayFlyway 其他用法bug错误Flyway版本不兼容数据库存在表了Flyway 的校验和(Checksum)不匹配 概要 在 Spring Boot 项目开发中,数据库的变更不可避免。手动执行 SQL 脚本不仅容易出错,也难以维…...
CAS单点登录(第7版)9.属性
如有疑问,请看视频:CAS单点登录(第7版) 属性 属性定义 概述 属性定义 从身份验证或属性存储库源获取和解析 CAS 中属性的定义时,往往使用其名称进行定义和引用,而无需任何其他元数据或修饰。例如&#…...
137,【4】 buuctf web [SCTF2019]Flag Shop
进入靶场 都点击看看 发现点击work会增加¥ 但肯定不能一直点下去 抓包看看 这看起来是一个 JWT(JSON Web Token)字符串。JWT 通常由三部分组成,通过点(.)分隔,分别是头部(Header&…...
P9853 [入门赛 #17] 方程求解
P9853 [入门赛 #17] 方程求解 - 洛谷 题目描述 小A有n个关于x的方程,第i个方程形如aixibici。方程的解x均为正整数,例如下面几个方程都是符合要求的方程: 2x 4 10 -3x 13 10 4x - 8 16 其中,第一组方程的解为x1…...
【网络安全 | 漏洞挖掘】跨子域账户合并导致的账户劫持与删除
未经许可,不得转载。 文章目录 概述正文漏洞成因概述 在对目标系统进行安全测试时,发现其运行着两个独立的域名——一个用于司机用户,一个用于开发者/企业用户。表面上看,这两个域名各自独立管理账户,但测试表明它们在处理电子邮件变更时存在严重的逻辑漏洞。该漏洞允许攻…...
spring集成activiti流程引擎(源码)
前言 activiti工作流引擎项目,企业erp、oa、hr、crm等企事业办公系统轻松落地,请假审批demo从流程绘制到审批结束实例。 源码获取:本文末个人名片直接获取。 一、项目形式 springbootvueactiviti集成了activiti在线编辑器,流行…...
ROS基本功能
1.Topic话题与Message消息(主要通讯方式) 基本规则 发布消息的步骤 常用工具 话题的订阅 使用launch启动多个节点...
C++基础系列【13】类的成员初始化
博主介绍:程序喵大人 35- 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇…...
Redis 03章——10大数据类型概述
一、which10 (1)一图 (2)提前声明 这里说的数据类型是value的数据类型,key的类型都是字符串 官网:Understand Redis data types | Docs (3)分别是 1.3.1redis字符串࿰…...
Ubuntu 上安装 Elasticsearch 7.6.0
要在 Ubuntu 24.04 上安装 Elasticsearch 7.6.0,可以按照以下步骤进行: 步骤 1: 更新系统依赖 确保系统是最新的,并安装必要的依赖包: sudo apt update sudo apt upgrade -y sudo apt install -y apt-transport-https openjdk-1…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
