设计模式12-构建器

设计模式12-构建器

      • 由来和动机
      • 原理思想
      • 构建器模式的C++代码实现
      • 构建器模式中的各个组件详解
        • 1. 产品类(Product)
        • 2. 构建类(Builder)
        • 3. 具体构建类(ConcreteBuilder)
        • 4. 指挥者类(Director)
      • 各个类的相互关系
      • 示例运行
      • 特点及其应用
      • 总结
  • 问题
    • 解答
      • 模板方法模式(Template Method Pattern)
      • 构造者模式(Builder Pattern)
      • 主要区别
      • 为什么构造者模式不能完全替代模板方法模式
      • 结论

构建器模式(Builder Pattern)是一种设计模式,主要用于分步骤创建一个复杂的对象。这种模式的主要动机是将一个复杂对象的构建过程与其表示相分离,使得同样的构建过程可以创建不同的表示。构建器模式特别适合创建那些包含很多子对象或者配置步骤的对象。构建器模式也是对象创建模式的一种。

由来和动机

  • 在软件系统中有时候面临着一个复杂对象的创建工作。通常由各个部分的子对象用一定的算法构成。由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化但是将他们组合在一起的算法却相对稳定。
  • 那么如何应对这种变化呢?如何提供一种封装机制来隔离除复杂对象的各个部分的变化?从而保持系统中的稳定,构建算法不随着需求的变化而变化。构建器模式就是为了解决这个问题而诞生的一种模式。构建器模式的动机就是将对象的创建过程分解为多个步骤,并通过一个构建器对象来逐步构建最终的复杂对象。

原理思想

构建器模式的核心思想是将对象的构建过程封装在一个独立的构建器对象中。构建器对象提供了一系列方法,用于设置对象的各个部分。最后,通过一个build()方法来返回最终的复杂对象。这种方式不仅使对象的构建过程清晰易懂,还使得不同的构建器可以创建不同类型的对象。

构建器模式的C++代码实现

下面是一个详细的C++代码示例,演示如何使用构建器模式来构建一个复杂的对象。

#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* getResult() = 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* getResult() override { return product_; }
private:Product* product_;
};// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product;  // 需要记得删除Product对象以避免内存泄漏return 0;
}

构建器模式中的各个组件详解

在构建器模式中,主要包括以下四个角色:产品类、构建类(抽象构建器)、具体构建类和指挥者类。下面是对每个角色的详细说明。

1. 产品类(Product)

作用:产品类是要构建的复杂对象。它包含多个组成部分,这些部分可以通过构建器来逐步设置。

结构:产品类包含表示最终复杂对象的各个部分(通常是成员变量),以及设置这些部分的方法。

示例代码

// 产品类
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_;
};

在这个示例中,Product类有三个部分(partA_partB_partC_),并提供了设置这些部分的方法。

2. 构建类(Builder)

作用:抽象构建器类定义了创建产品各个部分的方法接口,但不实现这些方法。它为具体构建器类提供了一个通用接口。

结构:抽象构建器类通常包含纯虚方法,这些方法用于创建产品的各个部分以及返回最终产品。

示例代码

// 构建器基类
class Builder {
public:virtual ~Builder() {}virtual void buildPartA() = 0;virtual void buildPartB() = 0;virtual void buildPartC() = 0;virtual Product* getResult() = 0;
};

在这个示例中,Builder类定义了四个纯虚方法,用于创建产品的各个部分和获取最终产品。

3. 具体构建类(ConcreteBuilder)

作用:具体构建器类实现了抽象构建器类定义的所有方法。它负责具体创建产品的各个部分,并返回最终产品。

结构:具体构建器类通常包含一个产品对象,并通过实现构建器接口的方法来设置产品的各个部分。

示例代码

// 具体构建器
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* getResult() override { return product_; }
private:Product* product_;
};

在这个示例中,ConcreteBuilder类实现了所有抽象构建器的方法,并在构建产品的过程中设置产品的各个部分。

4. 指挥者类(Director)

作用:指挥者类负责控制构建过程。它按照一定的顺序调用构建器的方法来创建产品。

结构:指挥者类通常包含一个构建器对象,并提供一个方法来执行产品的构建过程。

示例代码

// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};

在这个示例中,Director类通过调用构建器的方法来构建产品,并返回最终的产品。

各个类的相互关系

  1. 产品类(Product):包含复杂对象的各个部分,并提供设置和显示这些部分的方法。
  2. 构建类(Builder):定义了创建产品各个部分的方法接口。
  3. 具体构建类(ConcreteBuilder):实现了抽象构建器类的方法,负责具体创建产品的各个部分。
  4. 指挥者类(Director):控制构建过程,通过调用构建器的方法按顺序创建产品。

示例运行

结合以上代码示例,运行以下main函数会生成并展示一个完整的产品:

int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product;  // 需要记得删除Product对象以避免内存泄漏return 0;
}

运行结果:

Product parts: PartA, PartB, PartC

通过以上详细说明和代码示例,可以清楚地理解构建器模式的结构和作用。构建器模式通过分步骤构建复杂对象,提高了代码的可读性和可维护性,并提供了更大的灵活性来创建不同类型的产品。

特点及其应用

特点:

  1. 分步骤构建:构建器模式将对象的构建过程分解为一系列步骤,每一步都可以独立进行。
  2. 可扩展性好:可以通过不同的具体构建器来创建不同的对象。
  3. 解耦构建过程和表示:构建器模式将对象的构建过程和表示解耦,使得相同的构建过程可以创建不同的表示。

应用场景:

  1. 复杂对象的创建:当创建一个复杂对象时,需要分步骤进行,而且每一步可能有不同的实现方式。
  2. 代码可读性和可维护性:当构建逻辑复杂且需要复用时,使用构建器模式可以使代码更清晰和易于维护。
  3. 配置对象:构建器模式适合用来创建那些包含多个配置项的对象,例如创建一个包含多个选项的配置文件。

总结

在这里插入图片描述

构建器模式是一种强大的设计模式,通过将对象的构建过程分离出来,使得复杂对象的创建变得更加灵活和可维护。在C++中,构建器模式可以通过定义一个产品类、一个抽象构建器类、一个具体构建器类以及一个指挥者类来实现。这种模式广泛应用于需要创建复杂对象的场景中,例如GUI库中的窗口构建、报表生成、游戏中的复杂角色创建等。

问题

在应用过程中是不是可以用构造者模式代替模版方法,完成变化与固定步骤的完全分离,如果不行为什么不行?

解答

构造者模式(Builder Pattern)和模板方法模式(Template Method Pattern)都是用于创建和管理对象的行为模式,但它们适用于不同的场景和问题。虽然它们都有助于将变化与固定步骤分离,但它们并不是可以互相替代的,因为它们解决的问题和实现方式不同。下面将详细说明两者的区别以及为什么不能直接用构造者模式代替模板方法模式。

模板方法模式(Template Method Pattern)

作用:模板方法模式定义了一个操作中的算法骨架,而将一些步骤的实现延迟到子类中。模板方法模式使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。

结构

  1. 抽象类:定义了一个模板方法,包含算法的骨架。模板方法调用了若干个抽象操作,这些操作在子类中实现。
  2. 具体类:实现了抽象类中定义的抽象操作。

示例代码

#include <iostream>class AbstractClass {
public:void templateMethod() {stepOne();stepTwo();stepThree();}virtual ~AbstractClass() {}protected:virtual void stepOne() = 0;virtual void stepTwo() = 0;virtual void stepThree() = 0;
};class ConcreteClass : public AbstractClass {
protected:void stepOne() override {std::cout << "ConcreteClass: Step One" << std::endl;}void stepTwo() override {std::cout << "ConcreteClass: Step Two" << std::endl;}void stepThree() override {std::cout << "ConcreteClass: Step Three" << std::endl;}
};int main() {ConcreteClass concreteClass;concreteClass.templateMethod();return 0;
}

运行结果:

ConcreteClass: Step One
ConcreteClass: Step Two
ConcreteClass: Step Three

构造者模式(Builder Pattern)

作用:构造者模式将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。

结构

  1. 产品类:表示要构建的复杂对象。
  2. 构建类(抽象构建器):定义了创建产品各个部分的方法接口。
  3. 具体构建类:实现了抽象构建器类的方法,负责具体创建产品的各个部分。
  4. 指挥者类:控制构建过程,通过调用构建器的方法按顺序创建产品。

示例代码(与之前相同):

// 产品类
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* getResult() = 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* getResult() override { return product_; }
private:Product* product_;
};// 指挥者类
class Director {
public:void setBuilder(Builder* builder) { builder_ = builder; }Product* construct() {builder_->buildPartA();builder_->buildPartB();builder_->buildPartC();return builder_->getResult();}
private:Builder* builder_;
};int main() {Director director;ConcreteBuilder builder;director.setBuilder(&builder);Product* product = director.construct();product->show();delete product;  // 需要记得删除Product对象以避免内存泄漏return 0;
}

主要区别

  1. 目的不同

    • 模板方法模式:用于定义一个算法的骨架,并允许子类实现其中的某些步骤。它的核心在于让子类决定某些步骤的具体实现,但算法的整体结构是固定的。
    • 构造者模式:用于分步骤创建一个复杂的对象。它的核心在于分离对象的构建过程和表示,使得同样的构建过程可以创建不同的表示。
  2. 实现方式不同

    • 模板方法模式:通过继承和方法重载实现。抽象类定义算法的骨架,具体类实现具体步骤。
    • 构造者模式:通过组合和逐步构建实现。构建器类定义了创建对象的各个部分的方法,指挥者类控制构建过程。
  3. 应用场景不同

    • 模板方法模式:适用于当一个算法的整体结构固定,但某些步骤的实现可以变化时。常用于框架和库中,定义一些通用算法,让用户实现具体步骤。
    • 构造者模式:适用于创建一个复杂对象,其构建过程可以分为多个步骤。常用于需要灵活创建复杂对象的场景。

为什么构造者模式不能完全替代模板方法模式

  1. 不同的设计意图:模板方法模式的设计意图是通过继承和方法重载来复用算法的整体结构,而构造者模式的设计意图是通过组合和分步骤构建来创建复杂对象。
  2. 适用场景不同:模板方法模式更适合于算法步骤固定但实现可以变化的场景,而构造者模式更适合于需要逐步创建复杂对象的场景。
  3. 实现方式不同:模板方法模式依赖于抽象类和具体类的继承关系,而构造者模式依赖于构建器和指挥者的组合关系。

结论

虽然构造者模式和模板方法模式都可以用于将变化与固定步骤分离,但它们的适用场景和实现方式不同,不能简单地互相替代。在设计模式的选择上,应根据具体问题的需求选择合适的模式,而不是试图用一种模式解决所有问题。

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

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

相关文章

kettle从入门到精通 第七十九课 ETL之kettle kettle读取数据库BLOB字段转换为文件

上一课我们讲解了如何将文件以二进制流的方式写入数据库&#xff0c;本节课我们一起学习下如何将二进制数据读取为文件。 1、将二进制流转换为文件这里主要用到了步骤【文本文件输出】。表输入步骤从表中读取blob字段&#xff0c;java代码定义二进制流转换为文件的全路径&#…

Apache Tomcat文件包含漏洞复现(详细教程)

1.漏洞原理 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;其安装后会默认开启ajp连接器&#xff0c;方便与其他web服务器通过ajp协议进行交互。属于轻量级应用服务器&#xff0c;在中小型系统和并发访问用户不是很多的场合下被普遍使用&#xff0c;是开发和…

设计模式13-单件模式

设计模式13-单件模式 写在前面对象性能模式典型模式1. 单例模式&#xff08;Singleton Pattern&#xff09;2. 享元模式&#xff08;Flyweight Pattern&#xff09;3. 原型模式&#xff08;Prototype Pattern&#xff09;4. 对象池模式&#xff08;Object Pool Pattern&#xf…

【Django】在vscode中新建Django应用并新增路由

文章目录 打开一个终端输入新建app命令在app下的views.py内写一个视图app路由引入该视图项目路由引入app路由项目(settings.py)引入app&#xff08;AntappConfig配置类&#xff09;运行项目 打开一个终端 输入新建app命令 python manage.py startapp antapp在app下的views.py内…

源代码加密软件有什么用?源代码怎么防泄密

在软件开发领域&#xff0c;源代码被视为软件的生命线&#xff0c;它包含了实现特定功能的算法、业务逻辑以及技术细节&#xff0c;是软件公司的核心竞争力所在。由于源代码的重要性&#xff0c;其安全防护变得尤为关键。一旦源代码泄露&#xff0c;企业不仅面临财务损失&#…

DevExpress WinForms自动表单布局,创建高度可定制用户体验(二)

使用DevExpress WinForms的表单布局组件可以创建高度可定制的应用程序用户体验&#xff0c;从自动安排UI控件到按比例调整大小&#xff0c;DevExpress布局和数据布局控件都可以让您消除与基于像素表单设计相关的麻烦。 P.S&#xff1a;DevExpress WinForms拥有180组件和UI库&a…

【JavaEE初阶】线程的概念及创建

目录 &#x1f4d5; 前言 &#x1f4d5; 认识线程&#xff08;Thread&#xff09; &#x1f6a9; 概念 &#x1f60a;线程是什么 &#x1f642; 为啥要有线程 &#x1f62d; 进程和线程的区别&#xff08;面试题重点&#xff09; &#x1f92d; Java的线程和操作系统线程…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(八)-无人机探测与避让(DAA)机制

目录 引言 5.6 探测与避让&#xff08;DAA&#xff09;机制 5.6.1 基于PC5的探测与避让&#xff08;DAA&#xff09;机制 引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Airc…

华为AR6300S路由器开启SSH远程登录

登录华为路由器&#xff1a; 使用控制台线连接到路由器的控制台端口或者通过Telnet或Web界面远程登录到设备。进入系统视图&#xff1a; 输入system-view&#xff08;或者简写为sys&#xff09;命令进入系统视图模式&#xff0c;这是配置全局参数的地方。生成RSA密钥对&#x…

2024年7月27日(星期六)骑行小河边村

2024年7月27日 (星期六&#xff09;骑行小河边村&#xff0c;早8:30到9:00&#xff0c;大观公园门口集合&#xff0c;9:00准时出发【因迟到者&#xff0c;骑行速度快者&#xff0c;可自行追赶偶遇。】 偶遇地点:大观公园门口集合 &#xff0c;家住东&#xff0c;西&#xff0…

NodeRed测试modbus RTU或modbus TCP通讯

目录标题 STEP1 添加modbus节点STEP2 查看是否安装成功STEP3 modbusTCP读取写入设置读取设置写入设置 STEP4 读写测试 STEP1 添加modbus节点 节点管理——控制板——安装 找到node-red-contrib-modbus&#xff0c;点击安装 STEP2 查看是否安装成功 安装成功后&#xff0c;左…

30.【C语言】函数系列下

1.嵌套调用 *定义&#xff1a;函数之间的互相调用 *例&#xff1a; int function1(int a, int b) {function2(b);//嵌套函数的调用return a; } //注意&#xff1a;不能将function2定义在function1的里面&#xff0c;这不叫嵌套函数的调用 void function2(int c) {} #include…

linux系统安装python3和pip

一、安装python 1、安装依赖环境 yum install gcc -y yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel yum install zlib zlib-devel openssl -y yum install openssl…

学习记录day16—— 数据结构 双向链表 循环链表

双向链表 1、概念 1&#xff09;就是从任意一个节点既能存储其前驱节点&#xff0c;又能存储后继节点 2)结构体中增加一个指向前驱节点的指针 //定义数据类型 typedef int datatype;//定义节点类型 typedef struct Node {union {int len;datatype data;};struct Node *prio; …

Nova Admin - 简洁干净、免费开源的后台管理系统,基于Vue3 / Vite5 / Typescript / Naive UI 等前端开发技术栈

今天看到一款 Vue3 后台管理 admin 系统&#xff0c;研究了一下发现很不错&#xff0c;推荐给大家。 Nova-admin 是一个颜值在线&#xff0c;风格清新、简洁干净后台管理模板&#xff0c;包含了平时常用的管理后台功能页面模板。基础的 UI 组件基于我之前推荐的 naive-ui 开发…

百度,有道,谷歌翻译API

API翻译 百度&#xff0c;有道&#xff0c;谷歌API翻译&#xff08;只针对中英相互翻译&#xff09;,其他语言翻译需要对应from&#xff0c;to的code 百度翻译 package fills.tools.translate; import java.util.ArrayList; import java.util.HashMap; import java.util.Lis…

ABAP+从SAP发出去的PDF文件在第三方系统出现乱码

这是一个 ABAP转换PDF调用函数CALL FUNCTION CONVERT_OTF的问题记录&#xff0c;关乎字体STSong-Light-ldentity-H 和 STSong-Light的区别 背景&#xff1a; 做了一个增强&#xff0c;是采购订单审批后自动发送采购订单PDF1到企业微信&#xff0c;用户再将企业微信收到的P…

最优化理论与方法-第十讲割平面法

文章目录 1. 原问题&#xff1a;2. 割平面法程序步骤2.1 第一次迭代2.2 第二次迭代2.3 第三次迭代 1. 原问题&#xff1a; 给定下列约束优化问题&#xff1a; ( P ) min ⁡ 3 x 1 2 2 x 2 2 s t . − 5 x 1 − 2 x 2 3 ≤ 0 , x ∈ X { x ∈ Z n ∣ 8 x 1 8 x 2 ≥ 1 , 0…

mysql的主从复制和读写分离:

mysql的主从复制和读写分离&#xff1a; 主从复制 面试必问&#xff1a;主从复制的原理 主从复制的模式&#xff1a; 1、mysql的默认模式&#xff1a; 异步模式 主库在更新完事务之后会立即把结果返回给从服务器&#xff0c;并不关心从库是否接受到&#xff0c;以及从库是…

【React】package.json 文件详解

文章目录 一、package.json 文件的基本结构二、package.json 文件的关键字段1. name 和 version2. description3. main4. scripts5. dependencies 和 devDependencies6. repository7. keywords8. author 和 license9. bugs 和 homepage 三、package.json 文件的高级配置1. 配置…