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

04创建型设计模式——建造者模式

一、建造者模式简介

建造者模式(Builder Pattern)又被称为生成器模式。它旨在构建一个复杂对象的各个部分,而不需要指定该对象的具体类。该模式特别适用于对象的构建过程复杂且需要多个步骤的情况。建造者模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。

建造者模式适用于:当一个对象的构建比较复杂,将一个对象的构建(?)和对象的表示(?)进行分离的情况

  1. 分离构建和表示
    建造者模式通过将复杂对象的构建过程与其表示分离开来,允许构建过程的变化不会影响到最终对象的表示。也就是说,构建者模式关注的是如何一步一步地构建一个对象,而不是最终对象是什么样的。

  2. 逐步构建
    该模式允许通过多个步骤(方法)来逐步构建对象,这些步骤可以是可选的或者是必需的。构建的顺序和内容可以被灵活控制。

GoF一书中对建造者模式的介绍

 二、建造者模式的用处

1. 复杂对象的构建

当一个对象的构建过程包含多个步骤或组件时,建造者模式可以帮助将这些步骤分开,从而使构建过程更加清晰和易于管理。例如,构建一个具有多种配置选项的复杂数据结构或图形用户界面(GUI)组件。

2. 构建过程的灵活性

建造者模式允许灵活地定制对象的创建过程,而无需修改对象的具体实现。例如,不同的建造者可以用于创建具有不同配置或特性的对象,而指挥者(Director)负责控制构建的步骤和顺序。

3. 解耦构建和表示

将对象的构建过程与表示分离,使得构建的过程和最终的对象类型可以独立变化。这种解耦使得系统更加灵活,易于扩展和维护。例如,你可以在不修改对象创建逻辑的情况下添加新的产品类型或更改产品的外观。

4. 支持逐步构建

对于需要逐步构建的对象,建造者模式可以逐步执行构建步骤。这样可以在构建过程中控制每个步骤的执行,并允许有选择地构建对象。例如,在构建复杂的报告或文档时,你可以按章节、段落等逐步添加内容。

5. 提高代码可读性和可维护性

通过将构建过程分解成多个清晰的步骤,建造者模式使得代码更加易读和易于维护。每个建造者只负责对象的一个方面的构建,使得构建过程更加模块化。

6. 支持复杂的构建逻辑

当对象的构建逻辑非常复杂,需要处理多种条件或选项时,建造者模式可以封装这些复杂的逻辑。这样,可以将构建逻辑集中在建造者类中,而客户端代码只需知道如何使用指挥者来创建对象

三、建造者模式的设计方法

 builder.cpp

#include <iostream>
#include <string>
#include <memory>// 产品
class House {
public:void setDoor(const std::string& door) {this->door = door;}void setWall(const std::string& wall) {this->wall = wall;}void setWindow(const std::string& window) {this->window = window;}void setFloor(const std::string& floor) {this->floor = floor;}const std::string& getDoor() const {return this->door;}const std::string& getWall() const {return this->wall;}const std::string& getWindow() const {return this->window;}const std::string& getFloor() const {return this->floor;}protected:std::string door;std::string wall;std::string window;std::string floor;
};// 工程队
class Builder {
public:virtual ~Builder() {}virtual void buildWall() = 0;virtual void buildDoor() = 0;virtual void buildWindow() = 0;virtual void buildFloor() = 0;virtual std::shared_ptr<House> getHouse() = 0;virtual void viewHouse() const = 0; // 标记为 const
};class VillaBuilder : public Builder {
public:VillaBuilder() : house(std::make_shared<House>()) {}void buildWall() override {house->setWall("别墅墙");}void buildDoor() override {house->setDoor("别墅门");}void buildWindow() override {house->setWindow("别墅窗户");}void buildFloor() override {house->setFloor("别墅地板");}std::shared_ptr<House> getHouse() override {return house;}void viewHouse() const override {std::cout << "这是一座好别墅,有" << house->getWall() << ", 有" << house->getWindow() << ", 有" << house->getDoor() << ", 有" << house->getFloor() << "!" << std::endl;}private:std::shared_ptr<House> house;
};class FlatBuilder : public Builder {
public:FlatBuilder() : house(std::make_shared<House>()) {}void buildWall() override {house->setWall("公寓墙");}void buildDoor() override {house->setDoor("公寓门");}void buildWindow() override {house->setWindow("公寓窗户");}void buildFloor() override {house->setFloor("公寓地板");}std::shared_ptr<House> getHouse() override {return house;}void viewHouse() const override {std::cout << "这是一座好公寓,有" << house->getWall() << ", 有" << house->getWindow() << ", 有" << house->getDoor() << ", 有" << house->getFloor() << "!" << std::endl;}private:std::shared_ptr<House> house;
};// 设计师
class Director {
public:Director(std::shared_ptr<Builder> builder) : builder(builder) {}void constructHouse() {builder->buildWall();   // 先建墙builder->buildWindow(); // 然后建窗户builder->buildDoor();   // 再建门builder->buildFloor();  // 最后建地板}void viewHouse() const {builder->viewHouse();}private:std::shared_ptr<Builder> builder;
};// 设计师请工程队按照图纸建造好房子(客户端)
void doWorking() {// 请一个建造别墅的工程队std::shared_ptr<Builder> builder = std::make_shared<VillaBuilder>();Director director(builder);director.constructHouse();director.viewHouse();// 请一个建造公寓的工程队builder = std::make_shared<FlatBuilder>();Director anotherDirector(builder);anotherDirector.constructHouse();anotherDirector.viewHouse();
}int main() {// 开工doWorking();return 0;
}

运行效果

 

  1. 产品(Product)
    产品是最终构建出来的复杂对象,它包含多个组成部分和属性。产品类通常有多个子类,具体实现可以因业务需求而异。

  2. 建造者(Builder)
    建造者接口定义了构建产品的各个部分的方法。每个具体的建造者实现这些方法,按照特定的步骤来构建产品。

  3. 具体建造者(ConcreteBuilder)
    具体建造者实现了建造者接口,负责具体的构建步骤。这些步骤包括创建产品的不同部分,并在最后将产品返回。

  4. 指挥者(Director)
    指挥者类负责按照特定的顺序调用建造者的方法来构建产品。它将建造者的具体实现与构建过程分开,使得构建过程与产品的具体类型解耦。

  5. 客户端(Client)
    客户端负责使用指挥者和建造者来构建产品。客户端通常不需要知道产品的具体构建过程或其组成部分。

四、总结

建造者模式模仿建筑行业的建造行为,设计师设计好图纸交给工程队,工程队根据图纸建造房子,房子建造好之后交给客户。设计的代码中将构造(设计师的图纸)和表示(工程队造的房子)完美分离,这样可以把复杂的部分简单化,最后有机地组合在一起最终形成我们想要的产品。

相关文章:

04创建型设计模式——建造者模式

一、建造者模式简介 建造者模式&#xff08;Builder Pattern&#xff09;又被称为生成器模式。它旨在构建一个复杂对象的各个部分&#xff0c;而不需要指定该对象的具体类。该模式特别适用于对象的构建过程复杂且需要多个步骤的情况。建造者模式是一种对象创建型模式之一&…...

前端开发中的代码规范

引言 在前端开发中&#xff0c;遵循良好的代码规范是非常重要的。这不仅能提高代码的可读性和可维护性&#xff0c;还能帮助团队成员更好地协作。本文将介绍一些前端开发中常用的代码规范&#xff0c;并探讨它们的重要性。 1. 代码规范的重要性 1.1 可读性 良好的代码规范可…...

WHAT - 远程控制机制

目录 1. 客户端-服务器架构2. 连接建立3. 数据传输4. 通信协议5. 安全性6. 远程控制软件示例7. 操作流程示例 远程控制别人的电脑涉及到技术和安全多个方面。其基本机制通常包括以下几个方面&#xff1a; 1. 客户端-服务器架构 远程控制软件通常采用客户端-服务器架构&#x…...

苹果手机录音功能在哪里?3招轻松打开手机录音

无论是记录重要的会议内容、捕捉生活中的美好瞬间&#xff0c;还是进行语言学习&#xff0c;苹果手机的录音功能都能提供极大的便利。那么&#xff0c;苹果手机录音功能在哪里呢&#xff1f;本文将为您揭示苹果手机录音功能的藏身之处&#xff0c;并通过3个简单步骤&#xff0c…...

RCE之突破长度限制

我们在写webshell时通常会遇到过滤&#xff0c;但除了过滤之外还可能会有长度限制&#xff0c;这里就简单说一下关于RCE突破长度限制的技巧 突破16位 例如&#xff1a;PHP Eval函数参数限制在16个字符的情况下 &#xff0c;如何拿到Webshell&#xff1f; <?php $param …...

Arduino控制带编码器的直流电机速度

Arduino DC Motor Speed Control with Encoder, Arduino DC Motor Encoder 作者 How to control dc motor with encoder:DC Motor with Encoder Arduino, Circuit Diagram:Driving the Motor with Encoder and Arduino:Control DC motor using Encoder feedback loop: How …...

LangChain与Elasticsearch向量数据库的完美结合

在过去的一年中&#xff0c;生成式 AI (Generative AI) 领域取得了显著的进展。许多新的服务和工具应运而生。其中&#xff0c;LangChain 已成为构建大语言模型 (LLM) 应用程序&#xff08;例如检索增强生成 (RAG) 系统&#xff09;最受欢迎的框架之一。该框架极大地简化了原型…...

element时间段选择器或时间选择器 只设置默认起始时间或者结束时间,不显示问题

element时间段选择器或时间选择器 只设置默认起始时间或者结束时间&#xff0c;不显示问题 <div v-for"(item,index) in [a,b]":key"item"><el-date-pickerv-if"b"v-model"value1[item]"type"datetimerange"value-…...

Vue 3 中,组件间传值有多种方式

在 Vue 3 中&#xff0c;组件间传值有多种方式&#xff0c;以下是几种常见的方式 父组件向子组件传值&#xff08;通过 props&#xff09;&#xff1a;以下是几个父组件向子组件传值的示例&#xff1a;示例 1&#xff1a;传递字符串示例 2&#xff1a;传递数字示例 3&#xff1…...

前置(3):npm 和npx异同点

npm&#xff08;Node Package Manager&#xff09;和npx&#xff08;Node Package Execute&#xff09;是两个密切相关但用途不同的命令行工具&#xff0c;它们都是Node.js生态系统中的重要组成部分。 npm 用途&#xff1a;npm是Node.js的包管理器&#xff0c;主要用于安装、…...

笔记(day17)集合概述、List、Set、比较器

集合Collection 一.概述 ​ 集合可以理解为数据结构的封装,根据不同的特性及操作性能进行分类 二.继承体系 三.Collection中常用方法 ​ collection是集合中的父类,所以collection中的方法是所有集合中都有的 ​ 集合中只能保存引用类型(Object),无法保存基本类型 ​ Colle…...

C语言从头学45——I/O函数(二)

本文继续学习I/O函数&#xff0c;并延续前文的编号。 (三)、sscanf() 函数 sscanf() 函数与scanf() 有些相似&#xff0c;不同之处sscanf() 是从已有的字符串里面获取数据&#xff1b;这个函数也是定义在stdio.h中。 功能&#xff1a;处理已经输入到计算机中的字…...

Python爬虫——爬取bilibili中的视频

爬取bilibili中的视频 本次爬取&#xff0c;还是运用的是requests方法 首先进入bilibili官网中&#xff0c;选取你想要爬取的视频&#xff0c;进入视频播放页面&#xff0c;按F12&#xff0c;将网络中的名称栏向上拉找到第一个并点击&#xff0c;可以在标头中&#xff0c;找到…...

为什么企业电销要用外呼系统

电销要使用外呼系统的原因主要有以下几点&#xff1a; 一、提升工作效率 * **自动拨号**&#xff1a;外呼系统能够自动拨打客户电话&#xff0c;减少电销人员手动拨号的时间&#xff0c;让他们将更多精力集中在与客户的沟通和交流上。 * **数据记录与管理**&#xff1a;系统能…...

Keepalived + Nginx 主备容灾方案介绍

Keepalived Nginx 主备容灾方案介绍 *服务器**IP地址**角色*Srv01192.168.249.100 VIP: 192.168.249.110NginxKeepaliveSrv02192.168.249.101NginxKeepalive 概述 Keepalived 和 Nginx 的组合是一个常见的高可用性&#xff08;HA&#xff09;方案&#xff0c;尤其适用于 Web…...

PHP、JavaScript代码审计工具

软件截图 1. GPT代码审计需要挂代理,和充值才可以使用 2. 全局搜索关键字 3. 危险函数搜索 4. 自动化代码审计 报告 下载地址 GitHub - yuag/Code-audit: 代码审计代码审计. Contribute to yuag/Code-audit development by creating an account on GitHub....

《向量数据库指南》——Ray Data+Anyscale解锁价值评估新篇章

在钧瓷这一古老而深邃的艺术领域中,每一位资深藏家与投资人都深知,随着市场的不断发展与扩大,信息的处理与分析能力对于精准判断、高效收藏与投资决策至关重要。尤其是当我们面对庞大的钧瓷数据库、复杂的交易记录、以及不断更新的市场趋势时,传统的数据处理方式往往显得力…...

知识改变命运 数据结构【杨辉三角(顺序表)】

杨辉三角 首先我们可以发现题目中返回类型是一个 这其实返回的类似与一个二维数组 我们大概分析下题目根据画图可知&#xff0c;我们可以把每一行的元素进行存储&#xff0c;然后再把每一行存储起来&#xff0c;然后就实现了题目 代码&#xff1a; public List<List<…...

Docker三剑客之Docker Engine

Docker Engine作为Docker的核心组件&#xff0c;其功能和重要性不言而喻。以下是对Docker Engine的详细介绍&#xff0c;内容涵盖其定义、核心组件、工作原理、配置方法、安全性以及最佳实践等多个方面&#xff0c;但由于篇幅限制&#xff0c;我将尽量在6000字以内概括性地介绍…...

【Qt】信号与槽(下)

目录 自定义信号 带参数的信号和槽 信号和槽存在的意义 信号与槽的连接方式 一对一 一对多 多对一 意义 信号和槽的其他说明 信号和槽的断开 使用Lambda表达式定义槽函数 信号与槽的优缺点 优点: 松散耦合 缺点: 效率较低 自定义信号 自定义槽函数是非常关键的&a…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制

使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下&#xff0c;限制某个 IP 的访问频率是非常重要的&#xff0c;可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案&#xff0c;使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...