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

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

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

概括地说,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.mzph.cn/bicheng/26746.shtml

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

相关文章

2. 音视频H264

视频软件基本流程 1.什么是H264 H.264是由ITU-T视频编码专家组&#xff08;VCEG&#xff09;和ISO/IEC动态图像专家组&#xff08;MPEG&#xff09;联合组成的联合视频组&#xff08;JVT&#xff0c;Joint Video Team&#xff09;提出的高度压缩数字视频编解码器标准 H265又名高…

席卷的B站《植物大战僵尸杂交版》V2.0.88整合包,PC和手机可用,含通关存档和视频教程!

今天给大家安利一款席卷B站&#xff0c;火爆全网的游戏——《植物大战僵尸杂交版》2.0.88整合包。 这个是网络上现存植物大战僵尸杂交版的最全整合&#xff0c;包含了修改工具&#xff0c;超强通关存档和高清工具。工具包有安装视频教程&#xff0c;支持手机版和pc多端使用&am…

家用洗地机前十名排行榜:2024十大热销款式好用不踩雷

洗地机强大的清洁力和高效的清洁效率&#xff0c;迅速代替了吸尘器、电动拖把、蒸汽拖把的位置&#xff0c;成为家庭地面清洁的新宠&#xff0c;各大厂商也纷纷上新自家新品。但是这个也造成了人们在挑选机型的时候无从下手&#xff0c;甚至很多新手购机&#xff0c;几乎对洗地…

Typora 破解、激活!亲测有效!2024 最新激活方法

Typora 破解、激活&#xff01;亲测有效&#xff01;2024 最新激活方法 Typora是一款简单易用的Markdown编辑器。 Markdown是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式&#xff0c;其目标是实现…

【Intel CVPR 2024】通过图像扩散模型生成高质量360度场景,只需要一个语言模型

在当前人工智能取得突破性进展的时代&#xff0c;从单一输入图像生成全景场景仍是一项关键挑战。大多数现有方法都使用基于扩散的迭代或同步多视角内绘。然而&#xff0c;由于缺乏全局场景布局先验&#xff0c;导致输出结果存在重复对象&#xff08;如卧室中的多张床&#xff0…

Armbian OS(基于ubuntu24) 源码编译mysql 5.7

最近弄了个S905X3的盒子刷完Armbian OS &#xff08;基于ubuntu24&#xff09;&#xff0c;开始折腾Arm64之旅。第一站就遇到了MySQL的问题&#xff0c;由于MySQL没有提供Arm64版本&#xff0c;又不想塞Docker镜像&#xff0c;因此选择源码来编译MySQL5.7。下面记录详细过程和遇…

Golang的GC

目录 介绍GC 概要 什么是根对象 三色标记法 什么情况下三色标记法会失效 屏障机制 “强-弱” 三色不变式 插入屏障 (强三色) 删除屏障(弱三色) Go 的混合写屏障机制 混合写屏障规则 介绍GC 概要 作用范围&#xff1a;只回收堆内存&#xff0c;不回收栈内存&#xf…

举个栗子!Tableau 技巧(276):学做径向柱状图(Radial Column Chart)

关于 径向柱状图&#xff08;Radial Column Chart&#xff09;&#xff0c;俗称环形柱状图。它的用法跟柱形图基本一致&#xff0c;不同之处在于它的值刻度是环形的&#xff0c;数值从内到外依次增加&#xff0c;柱子越长代表数值越大。 数据粉可能会问&#xff1a;径向柱形图…

独具韵味的移动端 UI 风格

独具韵味的移动端 UI 风格

10.GLM

智谱AI GLM 大模型家族 最强基座模型 GLM-130B GLM (General Language Model Pretraining with Autoregressive Blank Infilling) 基于自回归空白填充的通用语言模型&#xff08;GLM&#xff09;。GLM通过增加二维位置编码并允许以任意顺序预测跨度来改进空白填充预训练&…

SQL 截取函数

目录 1、substring 2、left 3、right 4、substring_index 1、substring 用途&#xff1a;字段截取从指定开始的字符开始&#xff0c;截取要的数&#xff1b;指定开始的字符数字可以用负的&#xff0c;指定开始的字符从后往前(向左)数&#xff0c;截取要的数不能为负。 语…

go语言 | 快速生成数据库表的 model 和 queryset

就是生成 model 目录的 xxx.go 和 xxx_gen.go 文件 使用的工具&#xff1a; 快速生成 model&#xff1a;gentool&#xff1a;https://github.com/go-gorm/gen/tree/master/tools/gentool 根据 model 生成 queryset&#xff1a;go-queryset&#xff1a;https://github.com/jirfa…

2024.6.13 作业 xyt

今日作业&#xff1a; 自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 要求&#xff1a;每行代码都有注释 #include "my06zuoye.h"My06zuoye::My06zuoye(QWidget *parent): QMainWindow(parent) {//设置大小&#xff08;窗口&#xf…

java1.8运行arthas-boot.jar运行报错解决

报错内容 输入java -jar arthas-boot.jar&#xff0c;后报错。 [INFO] JAVA_HOME: D:\developing\jdk\jre1.8 [INFO] arthas-boot version: 3.7.2 [INFO] Can not find java process. Try to run jps command lists the instrumented Java HotSpot VMs on the target system.…

诚邀加盟!2025-CISP深圳国际体育展展位预定开启,共享发展机遇

2025-CISP深圳国际体育展定档官宣于2025年2月27-3月1日在深圳&#xff08;福田&#xff09;会展中心隆重开幕&#xff01;招商工作正式开启&#xff01; 体育创新融入现代生活&#xff0c;打造全球体育创新企业发布产品信息、展示前沿科技及倡导科学运动生活方式的全新平台。届…

为中小制造企业注入数字化转型活力

劳动力成本上升,原材料价格上涨,企业生产成本逐年增加&#xff0c;市场竞争越来越激烈&#xff0c;传统的中小制造企业面临着巨大的压力。 通过数字化转型应对环境的变化已成为行业共识&#xff0c;在数字化的进程中&#xff0c;中小企业首要考虑生存问题&#xff0c;不能沿用…

RPC(远程过程调用):技术原理、应用场景与发展趋势

摘要&#xff1a; RPC&#xff08;Remote Procedure Call&#xff09;是一种通信协议&#xff0c;用于实现跨网络的进程间通信。它提供了一种简单高效的方式&#xff0c;使得分布式系统中的不同组件能够像调用本地函数一样调用远程函数。本篇博客将介绍RPC的基本概念&#xff0…

【主要推荐算法概览,包括召回与排序】

文章目录 1、基于内容的推荐协同过滤推荐两大类2、召回算法2.1、基于规则策略的召回2.2、5类基础召回算法2.2.1、关联规则召回算法2.2.2、聚类召回算法2.2.3、朴素贝叶斯召回算法2.2.4、协同过滤召回算法2.2.5、矩阵分解召回算法 2.3、基于复杂算法的召回2.3.1、嵌入方法召回&a…

springboot+vue3前后端项目-部署Docker详解

一、后端yml环境配置 mysql和redis的连接之前是localhost。现在我们需要修改成容器之间的调用&#xff0c;如何知道mysql和redis的连接地址呢&#xff1f;docker compose就帮我们解决了这个问题&#xff0c;我们可以使用镜像容器的服务名称来表示链接。比如docker-compose.yml…

龙芯+RT-Thread+LVGL实战笔记(36)——密码锁完善

【写在前面】不知不觉中,又临近学期末了。这个学期,因为一些特殊原因,一直没怎么更新本教程,而且不得已上调了本教程的价格,在此笔者深表歉意。另一方面,自己带的学生发挥不佳,很遗憾未能闯进国赛,为此笔者也郁闷了相当长一段时间。事已至此,也只能慢慢释然,来年再战…