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

devtools/2024/10/18 9:21:58/

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

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

概括地说,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.ppmy.cn/devtools/51008.html

相关文章

python爬虫入门:批量下载图片

引言: 爬虫也被称为网络蜘蛛(Spider),是一种自动化的软件程序,能够在互联网上漫游,按照一定的规则和算法抓取数据。 爬虫技术广泛应用于搜索引擎、 数据挖掘 、信息提取等领域,是互联网技术的重要组成部分。 摘要: 很多初学者对于一个这样新奇的事务当然愿意去探索,…

【计算机视觉】人脸算法之图像处理基础知识(四)

图像的几何变换 图像的几何变换是指在不改变图像内容的前提下对图像的像素进行空间几何变换。主要包括图像的平移变换、镜像变换、缩放和旋转等。 1.插值算法 插值通常用来放缩图像大小&#xff0c;在图像处理中常见的插值算法有最邻近插值法、双线性插值法、二次立方、三次…

05 SpringBoot 配置文件详解-application.properties

Spring Boot 提供了大量的自动配置&#xff0c;极大地简化了spring 应用的开发过程&#xff0c;当用户创建了一个 Spring Boot 项目后&#xff0c;即使不进行任何配置&#xff0c;该项目也能顺利的运行起来。当然&#xff0c;用户也可以根据自身的需要使用配置文件修改 Spring …

一文彻底理解机器学习 ROC-AUC 指标

在机器学习和数据科学的江湖中&#xff0c;评估模型的好坏是非常关键的一环。而 ROC&#xff08;Receiver Operating Characteristic&#xff09;曲线和 AUC&#xff08;Area Under Curve&#xff09;正是评估分类模型性能的重要工具。 这个知识点在面试中也很频繁的出现。尽管…

Selenium 定位编辑框有span

当使用Selenium进行网页自动化测试时&#xff0c;定位一个包含span元素的编辑框可能会有些棘手&#xff0c;因为span通常用于对其他HTML元素进行分组或应用样式&#xff0c;而不一定是真正的可输入字段。不过&#xff0c;一旦我们确定了正确的策略&#xff0c;定位编辑框还是相…

mac m芯片安装win11遇坑

mac m芯片安装win11遇坑 1、下载arm架构镜像 磁力链接&#xff1a; magnet:?xturn:btih:e8c15208116083660709eac9aee124e025c01447&dnSW_DVD9_Win_Pro_11_22H2_64ARM_ChnSimp_Pro_Ent_EDU_N_MLF_X23-12755.ISO&xl57198960642、使用VMWare Fusion安装&#xff0c;启…

Django之云存储(一)

一、介绍 用户上传的文件以及项目中使用的静态文件,除了保存在本地服务器,还在可以保存在云服务中,比如: 阿里云七牛云(课程选用)亚马逊云等1.1、使用方式 注册账号 七牛云开发者平台 实名认证 创建空间

CyberDAO:引领Web3时代的DAO社区文化

致力于Web3研究和孵化 CyberDAO自成立以来&#xff0c;致力于推动Web3研究和孵化&#xff0c;吸引了来自技术、资本、商业、应用与流量等领域的上千名热忱成员。我们为社区提供多元的Web3产品和商业机会&#xff0c;触达行业核心&#xff0c;助力成员捕获Web3.0时代的红利。 目…