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

设计模式之生成器模式

目录

1.简介

2.结构

3.使用场景

4.实例

5.优缺点

6.与其他模式的关系

7.总结


1.简介

        生成器模式(Builder Pattern)是一种创建型设计模式,它允许你通过一步一步构建复杂对象,而不是通过一个包含大量参数的构造函数或方法。该模式特别适用于需要生成的对象具有多个可选属性,且这些属性的组合会导致大量构造函数重载的情况。

        生成器模式通过将对象的构建过程分解成多个步骤,使得每一步都可以单独配置。这样不仅提高了代码的可读性和可维护性,还使得构建过程更加灵活和可扩展。

        与其他创建型模式不同的是,生成器模式允许你在一个过程中创建一个对象,而无需等待所有部分都准备好。这种模式特别适用于需要构造不同表示或状态的复杂对象时。

2.结构

        生成器模式的UML结构图如下所示:

1) 生成器(Builder)接口声明在所有类型生成器中通用的产品构造步骤。
2) 具体生成器(Concrete Builders)提供构造过程的不同实现。具体生成器也可以构造不遵循通用接口的产品。
3) 产品(Products)是最终生成的对象。由不同生成器构造的产品无需属于同一类层次结构或接口。
4) 主管(Director)类定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置。
5) 客户端(Client)必须将某个生成器对象与主管类关联。一般情况下,你只需通过主管类构造函数的参数进行一次性关联即可。此后主管类就能使用生成器对象完成后续所有的构造任务。但在客户端将生成器对象传递给主管类制造方法时还有另一种方式。在这种情况下,你在使用主管类生产产品时每次都可以使用不同的生成器。

3.使用场景

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

        假设你的构造函数中有十个可选参数,那么调用该函数会非常不方便;因此,你需要重载这个构造函数,新建几个只有较少参数的简化版。但这些构造函数仍需调用主构造函数,传递一些默认数值来替代省略掉的参数。生成器模式让你可以分步骤生成对象,而且允许你仅使用必须的步骤。应用该模式后,你再也不需要将几十个参数塞进构造函数里了。

2)当你希望使用代码创建不同形式的产品(例如石头或木头房屋)时,可使用生成器模式。

        如果你需要创建的各种形式的产品,它们的制造过程相似且仅有细节上的差异,此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤,具体生成器将实现这些步骤来制造特定形式的产品。同时,主管类将负责管理制造步骤的顺序。

3)使用生成器构造组合树或其他复杂对象

        当一个对象的构建过程非常复杂,涉及多个步骤和多个部件时,使用生成器模式可以将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

        例如,构建一个汽车对象可能涉及设置车身、引擎、车轮和内饰等多个部件,每个部件都有多种选择。使用生成器模式,可以逐步构建汽车对象,并根据需要选择不同的部件。

4.实例

下面我将展示一个稍微复杂一些的应用场景,即构建一个包含多个可选组件的计算机配置对象。

首先,我们定义一个Computer类,它代表我们要构建的计算机对象:

#include <iostream>
#include <string>
#include <vector>
#include <memory>class Computer {
private:std::string caseType;std::string cpu;std::string gpu;std::string ram;std::string storage;std::vector<std::string> peripherals;// 禁止直接实例化Computer(const std::string& caseType, const std::string& cpu, const std::string& gpu,const std::string& ram, const std::string& storage,const std::vector<std::string>& peripherals): caseType(caseType), cpu(cpu), gpu(gpu), ram(ram), storage(storage), peripherals(peripherals) {}friend class ComputerBuilder;public:void display() const {std::cout << "Case Type: " << caseType << "\n";std::cout << "CPU: " << cpu << "\n";std::cout << "GPU: " << gpu << "\n";std::cout << "RAM: " << ram << "\n";std::cout << "Storage: " << storage << "\n";std::cout << "Peripherals: ";for (const auto& peripheral : peripherals) {std::cout << peripheral << " ";}std::cout << "\n";}
};

接下来,我们定义一个ComputerBuilder类,用于逐步构建Computer对象:

class ComputerBuilder {
protected:std::string caseType;std::string cpu;std::string gpu;std::string ram;std::string storage;std::vector<std::string> peripherals;public:virtual ~ComputerBuilder() = default;ComputerBuilder& setCaseType(const std::string& caseType) {this->caseType = caseType;return *this;}ComputerBuilder& setCpu(const std::string& cpu) {this->cpu = cpu;return *this;}ComputerBuilder& setGpu(const std::string& gpu) {this->gpu = gpu;return *this;}ComputerBuilder& setRam(const std::string& ram) {this->ram = ram;return *this;}ComputerBuilder& setStorage(const std::string& storage) {this->storage = storage;return *this;}ComputerBuilder& addPeripheral(const std::string& peripheral) {peripherals.push_back(peripheral);return *this;}virtual Computer build() const = 0;
};

注意,这里我们将ComputerBuilder定义为一个抽象类,并声明了一个纯虚函数build,这样我们就可以有不同的具体实现来构建不同类型的计算机。

现在,我们定义一个具体的GamingComputerBuilder类来构建游戏计算机:

class GamingComputerBuilder : public ComputerBuilder {
public:GamingComputerBuilder() {// 可以设置一些默认配置setCaseType("ATX Mid Tower");setCpu("Intel i9");// ... 其他默认配置}Computer build() const override {return Computer(caseType, cpu, gpu, ram, storage, peripherals);}
};

GamingComputerBuilder中,我们可以设置一些默认配置,或者覆盖父类的方法来提供特定的配置选项。

最后,我们定义一个ComputerDirector类(可选)来管理构建过程,并展示如何使用这些类来构建一个计算机对象:

class ComputerDirector {
private:ComputerBuilder* builder;public:ComputerDirector(ComputerBuilder* builder) : builder(builder) {}void setBuilder(ComputerBuilder* builder) {this->builder = builder;}Computer constructGamingComputer() {builder->setGpu("NVIDIA RTX 3090");builder->setRam("32GB DDR4");builder->setStorage("2TB SSD");builder->addPeripheral("Gaming Keyboard");builder->addPeripheral("Gaming Mouse");// ... 其他配置return builder->build();}
};int main() {GamingComputerBuilder gamingBuilder;ComputerDirector director(&gamingBuilder);// 或者使用自定义的构建步骤// gamingBuilder.setCaseType("Custom Case");// ... 其他设置// Computer customComputer = gamingBuilder.build();Computer gamingComputer = director.constructGamingComputer();gamingComputer.display();return 0;
}

在这个例子中,我们展示了如何使用生成器模式来构建一个包含多个可选组件的计算机配置对象。通过定义抽象的ComputerBuilder类和具体的GamingComputerBuilder类,我们可以灵活地构建不同类型的计算机,并且可以通过ComputerDirector类来管理构建过程(尽管在这个例子中ComputerDirector是可选的,但在更复杂的场景中它可能会很有用)。

5.优缺点

优点:

● 你可以分步创建对象,暂缓创建步骤或递归运行创建步骤。
● 生成不同形式的产品时,你可以复用相同的制造代码。
● 单一职责原则。你可以将复杂构造代码从产品的业务逻辑中分离出来。

缺点:

由于该模式需要新增多个类,因此代码整体复杂程度会有所增加。

6.与其他模式的关系

与工厂模式的关系

  • 工厂模式:主要用于生产各种对象,这些对象通常是兄弟类,继承自同一个基类。兄弟子类通过实现基类接口,展现不同的行为,并由工厂函数创建。然而,工厂模式在创建对象时并不关注构造细节,因此在处理复杂对象的生成时可能会显得力不从心。
  • 生成器模式:同样用于对象的生成,但更侧重于构造细节,增加了额外的构建流程,以便处理复杂对象的构建需求。生成器模式将对象构造的代码从产品类中抽取出来,放在一个名为生成器的独立对象中,并允许通过不同的生成器来创建不同形式的对象。
  • 对比:相较于工厂模式,生成器模式提供了更灵活和详细的对象构造方式。当对象相对简单时,可以使用工厂模式;而当对象复杂且需要详细配置时,生成器模式则更为适用。

与抽象工厂模式的关系

  • 抽象工厂模式:专注于生成一系列相关对象,但它在对象构造复杂时,其能力也有限。抽象工厂模式通过定义一个接口,使得客户端可以创建相关或依赖对象的家族,而无需明确指定具体类。
  • 生成器模式:虽然也用于创建对象,但更侧重于对象的逐步构造和细节配置。生成器模式允许开发者通过不同的生成器来创建具有不同配置和形式的对象。
  • 联系与区别:两者都提供了对象的创建方式,但抽象工厂模式更侧重于对象的家族创建,而生成器模式则更侧重于对象的逐步构造和细节配置。此外,抽象工厂模式通常会立即返回产品,而生成器模式则允许在获取产品前执行一些额外的构造步骤。

与其他模式的关系

  • 桥接模式:生成器模式可以与桥接模式结合使用,其中主管类负责抽象工作,而各种不同的生成器负责实现工作。这种结合可以使得对象构造更加灵活和可扩展。
  • 原型模式:原型模式通过复制现有对象来创建新对象,而生成器模式则通过逐步构造来创建对象。虽然两者在对象创建方式上有所不同,但在某些情况下,它们可以相互补充,共同实现复杂的对象创建需求。
  • 单例模式:抽象工厂、生成器和原型模式都可以用单例来实现,以确保对象的唯一性和全局可访问性。然而,这种实现方式并不常见,因为它可能会增加系统的复杂性和维护成本。

7.总结

        生成器模式通过将复杂对象的构建过程与表示分离,使得同样的构建过程可以创建不同的表示。它允许逐步构建对象,通过调用生成器对象的方法来添加或修改对象的部件。

相关文章:

设计模式之生成器模式

目录 1.简介 2.结构 3.使用场景 4.实例 5.优缺点 6.与其他模式的关系 7.总结 1.简介 生成器模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许你通过一步一步构建复杂对象&#xff0c;而不是通过一个包含大量参数的构造函数或方法。该…...

python学opencv|读取图像(三)放大和缩小图像

【1】引言 前序已经学习了常规的图像读取操作和图像保存技巧&#xff0c;相关文章链接为&#xff1a; python学opencv|读取图像-CSDN博客 python学opencv|读取图像&#xff08;二&#xff09;保存彩色图像-CSDN博客 今天我们更近一步&#xff0c;学习放大和缩小图像的技巧&…...

1 数据库(上):MySQL的概述和安装、SQL简介、IDEA连接数据库使用图形化界面

文章目录 前言一、数据库相关的概念二、MySQL概述1 MySQL的安装和配置2 MySQL登录、退出&#xff08;1&#xff09;mysql -uroot -p1234 或者mysql -uroot -p ---- 登录&#xff08;2&#xff09;exit或者quit ---- 退出 3 远程登录服务器上的MySQL命令mysql -hip地址 -P3306 -…...

C++初阶—类与对象(中篇)

第一章&#xff1a;类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&a…...

Leetcode15. 三数之和(HOT100)

链接 一般这种三数之和&#xff0c;四数之和都使用双指针&#xff0c;复杂度最优&#xff0c;次一级可使用哈希表。前者要求有序&#xff0c;后者空间上有花费。 题目&#xff1a; 题目要求答案中不能出现重复vector&#xff0c;比如{-1 1 0}和{-1 0 1}&#xff1b; 这两个…...

Oracle数据库小白备忘

sqlplus相关 导入sql文件 在sqlplus中&#xff0c;导入一个sql文件&#xff0c;是使用或者start。 如当前目录下有一个hello.sql&#xff0c;则可以使用 hello.sql 或者 start hello.sql 来进行导入&#xff0c;功能类似于mysql里面的source。 退出编辑模式 当使用sqlplus…...

DDR4与DDR3服务器内存的关键区别有哪些?

内存作为服务器性能的关键组件之一&#xff0c;已经经历了从DDR3到DDR4的过渡。DDR4内存相较于DDR3在多个方面有所提升&#xff0c;包括速度、带宽、功耗以及数据传输效率等。然而&#xff0c;尽管DDR4内存在性能上占有优势&#xff0c;DDR3内存依然在一些特定场景中得到了广泛…...

Linux: shell: bash: set -x;调试使用

man bash set -x -x After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list. 这个可以帮助将变量…...

Hadoop生态圈框架部署 伪集群版(五)- HBase伪分布式部署

文章目录 前言一、Hbase伪分布式部署&#xff08;手动部署&#xff09;1. 下载Hbase2. 上传安装包3. 解压HBase安装包4. 配置HBase配置文件4.1 修改hbase-env.sh配置文件4.2 修改hbase-site.xml配置文件4.3 修改regionservers配置文件4.4 删除hbase中slf4j-reload4j-1.7.33.jar…...

自定义指令,全局,局部,注册

让输入框自动获取焦点(每次刷新自动获取焦点&#xff09; <template><div><h3>自定义指令</h3><input ref"inp" type"text"></div> </template><script> export default {mounted(){this.$refs.inp.focus…...

静坐修心.

文章目录 打坐的历史文化渊源东方的起源与传承西方的接受与演变现代生活中的打坐 盘腿坐对身体的影响促进脊椎健康改善呼吸系统功能增强消化系统机能改善血液循环调节神经系统错误姿势及其他潜在危害 盘腿坐对心理的作用促进内心平静与放松提升自我觉察与内在探索培养专注力与精…...

设计模式c++(一)

文章目录 一、面向对象设计原则二、模版方法三、策略模式四、观察者模式五、装饰模式六、桥模式七、工厂方法_Factory Method八、抽象工厂_Abstract Factory九、原型模式十、构建器_builder十一、单件模式_Singleton十二、享元模式_Flyweight 一、面向对象设计原则 设计模式的…...

核密度估计——从直方图到核密度(核函数)估计_带宽选择

参考 核密度估计&#xff08;KDE&#xff09;原理及实现-CSDN博客 机器学习算法&#xff08;二十一&#xff09;&#xff1a;核密度估计 Kernel Density Estimation(KDE)_算法_意念回复-GitCode 开源社区 引言 在统计学中&#xff0c;概率密度估计是一种重要的方法&#xff0…...

Vant UI Axure移动端元件库:提升移动端原型设计效率

UI框架的选择对于提升开发效率和用户体验至关重要。Vant UI&#xff0c;作为一款基于Vue.js的轻量、可靠的移动端组件库&#xff0c;自2017年开源以来&#xff0c;凭借其丰富的组件库、良好的性能以及广泛的兼容性&#xff0c;在移动端开发领域崭露头角&#xff0c;赢得了众多开…...

如何用 JavaScript 操作 DOM 元素?

如何用 JavaScript 操作 DOM 元素&#xff1f;——结合实际项目代码示例讲解 在前端开发中&#xff0c;DOM&#xff08;文档对象模型&#xff09;操作是与页面交互的核心。通过 DOM 操作&#xff0c;开发者可以动态地修改页面内容、响应用户交互、控制样式等。JavaScript 提供…...

【Ubuntu】URDC(Ubuntu远程桌面助手)安装、用法,及莫名其妙进入全黑模式的处理

1、简述 URDC是Ubuntu远程桌面助手的简称。 它可以: 实时显示桌面:URDC支持通过Windows连接至Ubuntu设备(包括x86和ARM架构,例如Jetson系列、树莓派等)的桌面及光标。远程操控双向同步剪切板多客户端连接:同一Ubuntu设备最多可同时被三台Windows客户端连接和操控,适用于…...

ES-DSL查询

term查询 因为精确查询的字段搜是不分词的字段&#xff0c;因此查询的条件也必须是不分词的词条。查询时&#xff0c;用户输入的内容跟自动值完全匹配时才认为符合条件。如果用户输入的内容过多&#xff0c;反而搜索不到数据。 语法说明&#xff1a; // term查询 GET /index…...

npm 设置镜像

要在npm中设置镜像&#xff0c;你可以使用npm config命令。以下是设置npm镜像的步骤&#xff1a; 临时使用淘宝镜像&#xff1a; npm --registry https://registry.npmmirror.com install package-name 永久设置镜像&#xff1a; npm config set registry https://registry…...

SpringMvc完整知识点一

SpringMVC概述 定义 SpringMVC是一种基于Java实现MVC设计模型的轻量级Web框架 MVC设计模型&#xff1a;即将应用程序分为三个主要组件&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&#xff09;。这种分离…...

STM32G4系列MCU双ADC多通道数据转换的应用

目录 概述 1 STM32Cube配置项目 1.1 基本参数配置 1.1.1 ADC1参数配置 1.1.2 ADC2参数配置 1.2 项目软件架构 2 功能实现 2.1 ADC转换初始化 2.2 ADC数据组包 3 测试函数 3.1 Vofa数据接口 3.2 输入数据 4 测试 4.1 ADC1 通道测试 4.2 ADC2 通道测试 概述 本文…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...