设计模式——建造者模式(生成器模式)

建造者模式(生成器模式)

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图
用了建造者模式,那么用户就只需要指定需要构建的类型就可以得到它们,而具体构造的细节和过程不需要知道
在这里插入图片描述

概括地说,Builder是为创建一个Product对象的各个部件指定的抽象接口
而ConcreteBuilder是具体的建造者,实现Builder接口,构造和装配各个部件,Product是具体的产品
Director是指挥者,是构建一个使用Builder接口的对象。

  • 什么时候需要用到建造者模式?
    当我们需要创建一些复杂的对象,这些对象内部构建间的顺序通常是稳定的,但是对象内部的构建通常面临着复杂的变化

  • 实现方法

    1. 清晰地定义通用步骤, 确保它们可以制造所有形式的产品。 否则你将无法进一步实施该模式。
    2. 在基本生成器接口中声明这些步骤。
    3. 为每个形式的产品创建具体生成器类, 并实现其构造步骤。
    4. 考虑创建主管类。 它可以使用同一生成器对象来封装多种构造产品的方式。
    5. 客户端代码会同时创建生成器和主管对象。 构造开始前, 客户端必须将生成器对象传递给主管对象。 通常情况下, 客户端只需调用主管类构造函数一次即可。 主管类使用生成器对象完成后续所有制造任务。 还有另一种方式, 那就是客户端可以将生成器对象直接传递给主管类的制造方法。
    6. 只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。 否则, 客户端应当通过生成器获取构造结果。

基本代码如下

#include <iostream>
#include <vector>
#include <string>using std::cout;// 当产品非常复杂并且需要大量配置的时候,使用生成器模式非常有意义
// 各种构造器的结果可能并不总是遵循相同的接口class Product1
{
public:std::vector<std::string> parts_;void ListParts() const{cout << "Product parts: ";for (size_t i = 0; i < parts_.size(); i++){if (parts_[i] == parts_.back()){cout << parts_[i];}else{cout << parts_[i] << ", ";}}cout << "\n\n";}
};// Builder 接口指定了创建 Product 对象不同部分的方法。
class Builder
{
public:virtual ~Builder(){};virtual void ProducePartA() const = 0;virtual void ProducePartB() const = 0;virtual void ProducePartC() const = 0;
};// ConcreteBuilder 类遵循Builder类提供的接口,并提供建造步骤的具体实现。因此ConcreteBuilder应该有许多个,实现方法可以不同
class ConcreteBuilder1 : public Builder
{
private:// 一个新的构建器实例应该包含一个空白的产品对象,用于进一步的组装。Product1 *product;public:ConcreteBuilder1(){this->Reset();}~ConcreteBuilder1(){delete product;}void Reset(){this->product = new Product1();}// 所有生产步骤均使用同一产品实例void ProducePartA() const override{this->product->parts_.push_back("PartA1");}void ProducePartB() const override{this->product->parts_.push_back("PartB1");}void ProducePartC() const override{this->product->parts_.push_back("PartC1");}// 具体构建器应该提供自己的方法来检索结果。// 这是因为不同类型的构建器可能会创建完全不同的产品,这些产品不遵循相同的接口。// 因此,此类方法不能在基本构建器接口中声明(至少在静态类型编程语言中不能)// 通常,在将最终结果返回给客户端后,构建器实例应该准备好开始生产另一个产品。// 这就是为什么在 `getProduct` 方法主体末尾调用 reset 方法是一种常见做法。// 但是,这种行为不是强制性的,您可以让构建器等待来自客户端代码的明确 reset 调用,然后再处理之前的结果。// 一旦调用 GetProduct,此函数的用户就有责任释放此内存。使用智能指针来避免内存泄漏可能是一个更好的选择Product1 *GetProduct(){Product1 *result = this->product;this->Reset();return result;}
};// Director 负责按照特定的顺序执行构建顺序,
class Director
{
private:Builder *builder;// Director 可与客户端代码传递给它的任何构建器实例配合使用。这样,客户端代码可能会改变新组装产品的最终类型。
public:void set_builder(Builder *builder){this->builder = builder;}// Director 可以使用相同的构建步骤构建多个产品变体void BuildMinimalViableProduct(){this->builder->ProducePartA();}void BuildFullFeaturedProduct(){this->builder->ProducePartA();this->builder->ProducePartB();this->builder->ProducePartC();}
};// 客户端代码创建一个构建器对象,将其传递给Director,然后启动构造过程。最终结果从构建器对象中检索。
void ClientCode(Director &director)
{ConcreteBuilder1 *builder = new ConcreteBuilder1();director.set_builder(builder);cout << "Standard basic product:\n";director.BuildMinimalViableProduct();Product1 *p = builder->GetProduct();p->ListParts();delete p;cout << "Standard full featured product:\n";director.BuildFullFeaturedProduct();p = builder->GetProduct();p->ListParts();delete p;// 也可以不使用Director类直接使用构造模式cout << "Custom product:\n";builder->ProducePartA();builder->ProducePartC();p = builder->GetProduct();p->ListParts();delete p;delete builder;
}int main()
{Director *director = new Director();ClientCode(*director);delete director;return 0;
}

输出

Standard basic product:
Product parts: PartA1Standard full featured product:
Product parts: PartA1, PartB1, PartC1Custom product:
Product parts: PartA1, PartC1

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

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

相关文章

山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(三十二)- 微服务(12)

目录 12.8 RestClient查询文档 12.8.1 快速入门 12.8.2 match&#xff0c; term&#xff0c;bool&#xff0c;range查询 12.8.3 排序和分页 12.8.4 高亮 12.8 RestClient查询文档 12.8.1 快速入门 Testvoid testMatchALL() throws IOException {// 1. 准备requestSearchReq…

Tita 360评估:有效 360度反馈流程的 10 大步骤

宣传过程 如果你的公司首次引入多方位反馈或 360 度反馈&#xff0c;那么向所有利益相关者描述这一流程至关重要。由于流程太新&#xff0c;很多人还不了解。确保参与该流程的每个人都了解其目的&#xff0c;以及将如何实施该流程和使用其结果。花时间在一对一会议、小组会议和…

MyBatis 动态 SQL 的详细内容讲解

1. MyBatis 动态 SQL 的详细内容讲解 文章目录 1. MyBatis 动态 SQL 的详细内容讲解2. 准备工作3. if 标签4. where 标签5. trim 标签6. set 标签7. choose when otherwise 标签8. foreach 标签8.1 批量删除8.2 批量添加 9. SQL 标签与 include 标签10. 总结&#xff1a;11. 最…

centos下创建raid6磁盘阵列

在CentOS系统中创建RAID 6阵列&#xff0c;可以使用mdadm工具。 以下是创建RAID 6阵列的基本步骤和示例代码&#xff1a; 安装mdadm工具&#xff08;如果尚未安装&#xff09;&#xff1a; sudo yum install mdadm 假设你有至少四个以上的磁盘设备&#xff08;例如 /dev/sdi…

2024年最新Microsoft Edge关闭自动更新的方法分享

这里写自定义目录标题 打开【服务】 打开【服务】 windows中搜索服务&#xff0c;如下图&#xff1a; 打开服务界面&#xff0c;找到“Microsoft Edge Update Service (edgeupdate)” 及 “Microsoft Edge Update Service (edgeupdatem)” 两个服务&#xff0c;设置为禁用

【DrissionPage】Linux上如何将https改为http

最近有个老板找我做一个自动化的程序&#xff0c;要求部署到Linux上 这是一个http协议的网站&#xff0c;chrome在默认设置下&#xff0c;会将http的网站识别成不安全的内容&#xff0c;然后自动将http转化成https访问 但是&#xff0c;这个http的网站它的加载项里既有http的…

开源大模型之辩:真假开源

目录 前言开源的定义什么是开源大模型&#xff1f;大模型时代首次出现闭源和开源“齐头并进”开源和闭源不是绝对对立的 大模型到底开源什么&#xff1f;传统开源软件与开源大模型的差别开源软件让开源大模型“受益匪浅” 不同大模型企业&#xff0c;开源、闭源策略不同开源…

安装操作系统1-Win10版本介绍及硬件要求

注意&#xff1a;安装系统&#xff0c;首先弄清有哪些版本及所需硬件环境。 1.Win10有哪些版本 微软将 Win10为以下7个版本&#xff1a; Windows 10 家庭版&#xff08;Home&#xff09; 面向所有普通用户&#xff0c;提供Win 10的基本功能。此版本适合个人家庭用户使用&am…

一维信号的时频分析(Python)

代码较为简单&#xff0c;很容易读懂。 Importing the required libraries import os import numpy as np import pywt import pandas as pd import pickle as pkl from matplotlib import pyplot as plt Parameters or Required Variables DATA_POINTS_PER_FILE 2560 TIM…

Android Jetpack Compose入门教程(二)

一、列表和动画 列表和动画在应用内随处可见。在本课中&#xff0c;您将学习如何利用 Compose 轻松创建列表并添加有趣的动画效果。 1、创建消息列表 只包含一条消息的聊天略显孤单&#xff0c;因此我们将更改对话&#xff0c;使其包含多条消息。您需要创建一个可显示多条消…

(代数:解一元二次方程)可以使用下面的公式求一元二次方程 ax2+bx+c0 的两个根:

(代数:解一元二次方程)可以使用下面的公式求一元二次方程 ax2bxc0 的两个根: b2-4ac 称作一元二次方程的判别式。如果它是正值,那么一元二次方程就有两个实数根。 如果它为 0&#xff0c;方程式就只有一个根。如果它是负值&#xff0c;方程式无实根。 编写程序&#xff0c;提示…

STM32存储左右互搏 模拟U盘桥接SPI总线FATS读写FLASH W25QXX

STM32存储左右互搏 模拟U盘桥接SPI总线FATS读写FLASH W25QXX STM32的USB接口可以模拟成为U盘&#xff0c;通过FATS文件系统对连接的存储单元进行U盘方式的读写。 这里介绍STM32CUBEIDE开发平台HAL库模拟U盘桥接SPI总线FATS读写W25Q各型号FLASH的例程。 FLASH是常用的一种非易失…

vs2019 c++20规范 STL 库中头文件 <atomic> 源码注释及探讨几个知识点

&#xff08;1 探讨一&#xff09; 模板类 atomic 的继承关系与数据结构如下&#xff1a; (2 探讨二 ) 可见 atomic 的 fetch_xx 函数&#xff0c;返回的都是 atomic 中存储的旧值。测试如下&#xff1a; 谢谢

无公网IP与服务器完成企业微信网页应用开发远程调试详细流程

文章目录 前言1. Windows安装Cpolar2. 创建Cpolar域名3. 创建企业微信应用4. 定义回调本地接口5. 回调和可信域名接口校验6. 设置固定Cpolar域名7. 使用固定域名校验 前言 本文主要介绍如何在企业微信开发者中心通过使用内网穿透工具提供的公网域名成功验证回调本地接口服务! …

互联网应用主流框架整合之SpringMVC初始化及各组件工作原理

Spring MVC的初始化和流程 MVC理念的发展 SpringMVC是Spring提供给Web应用领域的框架设计&#xff0c;MVC分别是Model-View-Controller的缩写&#xff0c;它是一个设计理念&#xff0c;不仅仅存在于Java中&#xff0c;各类语言及开发均可用&#xff0c;其运转流程和各组件的应…

PFC旁路二极管、继电器驱动电路以及PFC主功率

R001和R002以及R003三个电阻作用是限放X电容上的电 整流桥串联两个BJ1和BJ2 电容C3:给整流桥储能&#xff0c;给后续llc供电 PFC工作是正弦波上叠加高频电流 PFC功率部分 2个PFC电感&#xff08;选择两个磁芯骨架小&#xff0c;有利于散热&#xff09;、2个续流二极管&…

【Hudi】核心概念-基本概念

目录 基本概念时间轴(TimeLine)Instant action:在表上执行的操作类型Instant timeState两个时间概念 文件布局(File Layout)索引(Index)原理索引选项全局索引与非全局索引索引的选择策略 表类型(Table Types)查询类型Snapshot QueriesIncremental QueriesRead Optimized Querie…

出现“由于找不到msvcr120.dll,无法继继续执行代码”提示的问题处理方法

本文章针对出现“由于找不到msvcr120.dll,无法继续执行代码”的问题进行深入剖析&#xff0c;并提供了两种有效的解决方案&#xff0c;方便大家能快速恢复正常工作状态。 一.关于msvcr120.dll文件部分介绍 “由于找不到msvcr120.dll,无法继续执行代码”常发生在我们打开一个软…

web端使用高德地图

web端使用高德地图 一、申请高德key和秘钥二、在项目中引入所需功能js、css文件三、实现地图选点、回显选点四、自定义地图 一、申请高德key和秘钥 申请高德key 申请成功后可以得到key 二、在项目中引入所需功能js、css文件 <script src"https://webapi.amap.com/m…

流程设计的基本步骤

背景 公司为什么要流程&#xff0c;已经有专门章节进行阐述&#xff1b; 什么是流程&#xff0c;已经有专门章节进行专门阐述&#xff1b; 那么接下来这个章节讨论&#xff0c;流程设计的基本步骤&#xff0c;那么谁来设计流程呢&#xff0c;让一个部门的员工来设计一份流程…