C++创建型模式之生成器模式

解决的问题

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

适用场景
  1. 复杂对象的构建:当对象的构建过程非常复杂,涉及多个步骤和多个部件时。
  2. 不同的构建过程:当需要不同的表示时,可以使用相同的构建过程。
  3. 逐步构建:当对象的构建过程可以逐步进行时。
模式的参与者角色
  1. Builder(生成器接口):定义构建产品的各个部件的抽象接口。
  2. ConcreteBuilder(具体生成器):实现 Builder 接口,负责构建产品的各个部件。
  3. Product(产品):表示正在构建的复杂对象。
  4. Director(指导者):使用 Builder 接口来构建产品。

以生产汽车为例的生成器模式示例代码

#include <iostream>
#include <string>

// 产品类:汽车
class Car {
public:
    void setBody(const std::string& body) { body_ = body; }
    void setEngine(const std::string& engine) { engine_ = engine; }
    void setWheels(const std::string& wheels) { wheels_ = wheels; }
    void setInterior(const std::string& interior) { interior_ = interior; }

    void show() const {
        std::cout << "Car Configuration: " << std::endl;
        std::cout << "Body: " << body_ << std::endl;
        std::cout << "Engine: " << engine_ << std::endl;
        std::cout << "Wheels: " << wheels_ << std::endl;
        std::cout << "Interior: " << interior_ << std::endl;
    }

private:
    std::string body_;
    std::string engine_;
    std::string wheels_;
    std::string interior_;
};

// 抽象生成器接口
class CarBuilder {
public:
    virtual ~CarBuilder() {}
    virtual void buildBody() = 0;
    virtual void buildEngine() = 0;
    virtual void buildWheels() = 0;
    virtual void buildInterior() = 0;
    virtual Car* getCar() = 0;
};

// 具体生成器:SUV 汽车
class SUVBuilder : public CarBuilder {
public:
    SUVBuilder() { car_ = new Car(); }
    ~SUVBuilder() { delete car_; }

    void buildBody() override { car_->setBody("SUV Body"); }
    void buildEngine() override { car_->setEngine("SUV Engine"); }
    void buildWheels() override { car_->setWheels("SUV Wheels"); }
    void buildInterior() override { car_->setInterior("SUV Interior"); }

    Car* getCar() override { return car_; }

private:
    Car* car_;
};

// 具体生成器:Sedan 汽车
class SedanBuilder : public CarBuilder {
public:
    SedanBuilder() { car_ = new Car(); }
    ~SedanBuilder() { delete car_; }

    void buildBody() override { car_->setBody("Sedan Body"); }
    void buildEngine() override { car_->setEngine("Sedan Engine"); }
    void buildWheels() override { car_->setWheels("Sedan Wheels"); }
    void buildInterior() override { car_->setInterior("Sedan Interior"); }

    Car* getCar() override { return car_; }

private:
    Car* car_;
};

// 指导者
class Director {
public:
    void setBuilder(CarBuilder* builder) { builder_ = builder; }

    Car* constructCar() {
        builder_->buildBody();
        builder_->buildEngine();
        builder_->buildWheels();
        builder_->buildInterior();
        return builder_->getCar();
    }

private:
    CarBuilder* builder_;
};

// 客户端代码
int main() {
    Director director;

    // 创建 SUV
    std::cout << "Building SUV..." << std::endl;
    SUVBuilder suvBuilder;
    director.setBuilder(&suvBuilder);
    Car* suv = director.constructCar();
    suv->show();
    delete suv;

    // 创建 Sedan
    std::cout << "\nBuilding Sedan..." << std::endl;
    SedanBuilder sedanBuilder;
    director.setBuilder(&sedanBuilder);
    Car* sedan = director.constructCar();
    sedan->show();
    delete sedan;

    return 0;
}

代码说明

  1. Car 类表示正在构建的汽车产品,包含汽车的各个部件。
  2. CarBuilder 是一个抽象生成器接口,定义了构建汽车各个部件的方法和一个获取最终产品的接口。
  3. SUVBuilder 和 SedanBuilder 是具体生成器类,分别实现了 CarBuilder 接口,用于构建 SUV 和 Sedan 汽车。
  4. Director 类负责使用 CarBuilder 接口来构建汽车。它通过调用生成器的各个构建方法来逐步构建汽车。
  5. Client 在 main 函数中使用 Director 和具体生成器来构建不同类型的汽车,并展示汽车配置。

总结

生成器模式通过将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。在需要逐步构建复杂对象或需要不同表示的场景中,生成器模式非常有用。

模板方法(Template Method)模式与生成器(Builder)模式

形式相似点
  1. 抽象类与具体类:两种模式都涉及抽象类(或接口)和具体实现类。
  2. 分步构建:都需要分步骤构建复杂对象或执行算法。
目的的不同点
  1. 模板方法模式:定义一个算法的框架,允许子类在不改变算法结构的情况下重新定义算法的某些步骤。目的是为了代码复用和算法的一致性。
  2. 生成器模式:将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。目的是为了构建复杂对象时的灵活性和可扩展性。

模板方法模式的代码示例

#include <iostream>
#include <string>

// 抽象类,定义模板方法
class AbstractClass {
public:
    // 模板方法
    void templateMethod() {
        step1();
        step2();
        step3();
    }

protected:
    virtual void step1() = 0;
    virtual void step2() = 0;
    virtual void step3() = 0;
};

// 具体类1
class ConcreteClass1 : public AbstractClass {
protected:
    void step1() override {
        std::cout << "ConcreteClass1: Step 1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClass1: Step 2" << std::endl;
    }

    void step3() override {
        std::cout << "ConcreteClass1: Step 3" << std::endl;
    }
};

// 具体类2
class ConcreteClass2 : public AbstractClass {
protected:
    void step1() override {
        std::cout << "ConcreteClass2: Step 1" << std::endl;
    }

    void step2() override {
        std::cout << "ConcreteClass2: Step 2" << std::endl;
    }

    void step3() override {
        std::cout << "ConcreteClass2: Step 3" << std::endl;
    }
};

// 客户端代码
int main() {
    AbstractClass* class1 = new ConcreteClass1();
    class1->templateMethod();
    delete class1;

    std::cout << std::endl;

    AbstractClass* class2 = new ConcreteClass2();
    class2->templateMethod();
    delete class2;

    return 0;
}

生成器模式的代码示例

#include <iostream>
#include <string>

// 产品类
class Product {
public:
    void setPartA(const std::string& partA) { partA_ = partA; }
    void setPartB(const std::string& partB) { partB_ = partB; }
    void setPartC(const std::string& partC) { partC_ = partC; }

    void show() const {
        std::cout << "Product parts: " << partA_ << ", " << partB_ << ", " << partC_ << std::endl;
    }

private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
};

// 抽象生成器接口
class Builder {
public:
    virtual ~Builder() {}
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product* getProduct() = 0;
};

// 具体生成器
class ConcreteBuilder : public Builder {
public:
    ConcreteBuilder() { product_ = new Product(); }
    ~ConcreteBuilder() { delete product_; }

    void buildPartA() override { product_->setPartA("PartA"); }
    void buildPartB() override { product_->setPartB("PartB"); }
    void buildPartC() override { product_->setPartC("PartC"); }

    Product* getProduct() override { return product_; }

private:
    Product* product_;
};

// 指导者
class Director {
public:
    void setBuilder(Builder* builder) { builder_ = builder; }

    Product* constructProduct() {
        builder_->buildPartA();
        builder_->buildPartB();
        builder_->buildPartC();
        return builder_->getProduct();
    }

private:
    Builder* builder_;
};

// 客户端代码
int main() {
    Director director;

    // 创建具体生成器
    ConcreteBuilder builder;
    director.setBuilder(&builder);

    // 构建产品
    Product* product = director.constructProduct();
    product->show();
    delete product;

    return 0;
}

代码说明

模板方法示例
  1. AbstractClass:定义了一个模板方法 templateMethod(),其中包含了三个抽象步骤 step1()step2()step3()
  2. ConcreteClass1 和 ConcreteClass2:具体子类,分别实现了抽象步骤,但模板方法的结构保持不变。
  3. 客户端代码:通过创建 ConcreteClass1 和 ConcreteClass2 的对象,调用 templateMethod() 方法来执行算法,子类可以在不改变算法结构的情况下重新定义算法的某些步骤。
生成器模式示例
  1. Product:表示正在构建的复杂对象。
  2. Builder:抽象生成器接口,定义了构建产品的各个部件的方法和一个获取最终产品的接口。
  3. ConcreteBuilder:具体生成器类,实现了 Builder 接口,负责构建产品的各个部件。
  4. Director:指导者类,使用 Builder 接口来构建产品。通过调用生成器的各个构建方法来逐步构建产品。
  5. 客户端代码:通过 Director 和 ConcreteBuilder 来构建产品,并展示产品配置。

总结

  • 模板方法模式:目的是为了代码复用和算法的一致性,通过定义算法的框架,允许子类在不改变算法结构的情况下重新定义算法的某些步骤。
  • 生成器模式:目的是为了构建复杂对象时的灵活性和可扩展性,通过将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IQ Offset之工厂实例分析

有个产品 其方块图如下: FEM全名为Front End Module 详情可参照这篇 [1] WIFI前端模块的解析 这边就不赘述 而在工厂大量生产时 有一块板子 其Chain1的EVM Fail 分析Log后 发现其IQ Offset的值 比Chain2/Chain3/Chain4 还要来得差 请问 问题是出在收发器? 还是…

音视频入门基础:MPEG2-TS专题(4)——使用工具分析MPEG2-TS传输流

一、引言 有很多工具可以分析MPEG2-TS文件/流&#xff0c;比如Elecard Stream Analyzer、PROMAX TS Analyser、easyice等。下面一一对它们进行简介&#xff08;个人感觉easyice功能更强大一点&#xff09;。 二、Elecard Stream Analyzer 使用Elecard Stream Analyzer工具可以…

任务调度工具Spring Test

Spring Task 是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑。 作用&#xff1a;定时自动执行某段Java代码 应用场景&#xff1a; 信用卡每月还款提醒 银行贷款每月还款提醒 火车票售票系统处理未支付订单 入职纪念日为用户发送通知 一.…

ORB-SLAM2 ---- Tracking::TrackWithMotionModel()

文章目录 一、函数作用二、函数讲解三、函数代码四、调用的函数1. Tracking::UpdateLastFrame()1&#xff09;. 函数讲解2&#xff09;. 函数代码 2. ORBmatcher::SearchByProjection()1&#xff09;. 函数讲解2&#xff09;. 函数代码 3. Optimizer::PoseOptimization(Frame *…

10月月报 | Apache DolphinScheduler进展总结

各位热爱 Apache DolphinScheduler 的小伙伴们&#xff0c;社区10月份月报更新啦&#xff01;这里将记录 DolphinScheduler 社区每月的重要更新&#xff0c;欢迎关注&#xff01; 月度Merge之星 感谢以下小伙伴10月份为 Apache DolphinScheduler 所做的精彩贡献&#xff08;排…

第5章-总体设计 5.3 硬件架构设计

5.3 硬件架构设计 1.哪些类型的产品需要架构设计&#xff1f;2.硬件架构师到底做什么&#xff1f;&#xff08;1&#xff09;理解需求和业务模型的情况。&#xff08;2&#xff09;背板设计&#xff0c;既需要考虑业务数据交换能力&#xff0c;也需要考虑子模块的管理监控能力。…

深度学习工具和框架详细指南:PyTorch、TensorFlow、Keras

引言 在深度学习的世界中&#xff0c;PyTorch、TensorFlow和Keras是最受欢迎的工具和框架&#xff0c;它们为研究者和开发者提供了强大且易于使用的接口。在本文中&#xff0c;我们将深入探索这三个框架&#xff0c;涵盖如何用它们实现经典深度学习模型&#xff0c;并通过代码…

windows 安装Ubuntu 后如何使用

windows 安装Ubuntu 后如何使用 youtube链接 https://www.youtube.com/watch?vPaEcQmgEz78哔哩哔哩视频 https://www.bilibili.com/video/BV1tW42197za/?spm_id_from333.999.0.0两个视频是一样的安装Ubuntu 安装docker的教程&#xff0c;不执行docker的安装即可 安装完毕后…

IDEA leetcode插件代码模板配置,登录闪退解决

前言 最近换电脑&#xff0c;配置idea时和原来的模板格式不一样有点难受&#xff0c;记录一下自己用的模板&#xff0c;后期换电脑使用&#xff0c;大家也可以使用&#xff0c;有更好的地方可以分享给我~ IDEA leetcode插件代码模板配置,登录闪退解决 前言1 下载IDEA leetcode…

kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署

前言&#xff1a;半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建&#xff0c;下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群&#xff08;单master节点 & 单master节点&#xff09;Prometheus监控部…

Node.js | npm下载安装及环境配置教程

前言&#xff1a; npm 是 Nodejs 下的包管理器&#xff0c;在下载 Node.js 后自动安装&#xff0c;因此本文同时适合 Node.js / npm 的下载安装及环境配置。 一、软件安装 Node.js中文网官网下载页&#xff1a;Node.js 中文网 (nodejs.com.cn) 1&#xff09;进入下载页&#xf…

C++ 的发展

目录 C 的发展总结&#xff1a;​编辑 1. C 的早期发展&#xff08;1979-1985&#xff09; 2. C 标准化过程&#xff08;1985-1998&#xff09; 3. C 标准演化&#xff08;2003-2011&#xff09; 4. C11&#xff08;2011年&#xff09; 5. C14&#xff08;2014年&#xf…

游戏引擎学习第14天

1. 为什么关注内存管理&#xff1f; 内存分配是潜在的失败点&#xff1a; 每次进行内存分配&#xff08;malloc、new等&#xff09;时&#xff0c;都可能失败&#xff08;例如内存不足&#xff09;。这种失败会引入不稳定性或不可预测性&#xff0c;需要额外的错误处理逻辑。 …

QT6学习第一天

QT6安装和示例运行 QT介绍QT特点QT开发框架QT Quick和QML介绍Qt Widgets和Qt QuickQT6下载安装QT Creator介绍QT Creator界面介绍 QT介绍 Qt是一个跨平台的应用程序和UI开发框架&#xff0c;可用于桌面、嵌入式和移动平台的应用程序和用户界面的开发。 使用Qt只需一次性开发应…

一文详细深入总结服务器选型

1. 题记&#xff1a; 服务器选型工作是项目规划检讨的一项非常重要的工作&#xff0c;本文详细深入总结服务器选型。 2. 服务器基础知识概览 2.1 服务器的定义与功能 2.1 .1 定义 服务器是一种高性能计算机&#xff0c;其设计目的是在网络中提供服务。它可以处理来自多个客…

打造旅游卡服务新标杆:构建SOP框架与智能知识库应用

随着旅游业的蓬勃兴起&#xff0c;旅游卡产品正逐渐成为市场的焦点。为了进一步提升服务质量和客户体验&#xff0c;构建一套高效且标准化的操作流程&#xff08;SOP&#xff09;变得尤为重要。本文将深入探讨如何构建旅游卡的SOP框架&#xff0c;并介绍如何利用智能知识库技术…

基于Python爬虫大屏可视化的热门旅游景点数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

04 - Clickhouse-21.7.3.14-2单机版安装

目录 一、准备工作 1、确定防火墙处于关闭状态 2、CentOS 取消打开文件数限制 3、安装依赖 4、CentOS取消SELINUX 二、单机安装 2.1、下载安装 2.2、安装这4个rpm包 2.3、修改配置文件 2.4、启动服务 2.5、关闭开机自启 2.6、使用Client连接server 一、准备工作 1…

uni-app移动端与PC端兼容预览PDF文件

过程遇到的问题 1、如果用的是最新的版本的pdfjs的话&#xff0c;就会报Promise.withResolvers 不是一个方法的错误&#xff0c;原因是Promise.withResolvers是ES15新特性&#xff0c;想了解可参考链接&#xff0c;这里的解决方案是将插件里的涉及到Promise.withResolvers的地…

shell编程--永久环境变量和字符串显位

环境变量 echo $HOME 在终端输出后会显示家目录有个root变量 我们会提出个疑问为什么平时我们在终端输入sl 或者which等等命令会输出一些内容呢&#xff0c;这是因为这些命令都有对应的环境变量。 我们查看一下环境变量 在终端输入&#xff1a; echo $PATH 我们看一下输出…