C++设计模式——Builder Pattern建造者模式

news2024/9/22 23:25:00

一,建造者模式的定义

建造者模式,又被称为生成器模式,是一种创建型设计模式,它将复杂产品的构建过程分解为一系列简单的步骤,每个步骤由独立的建造者对象负责。

建造者模式常用于创建复杂的对象,它避免了直接传递大量参数来构造函数,使得构建过程变得可控,让代码变得灵活和可维护。

建造者模式允许开发者按照指定的步骤创建复杂对象,构建过程的细节被封装在具体建造者中,将创建对象的过程和表示对象的过程分离,且同一个构建过程可以使用不同的具体建造者以及不同的顺序来创建不同的表示。

建造者模式在现实生活中的抽象实例:

建筑分工:将一个复杂的建筑物分解成多个简单的部分,然后由不同的建筑工人来负责建造每个部分,最后将这些部分组装构建成完整的建筑物。

餐厅菜单:餐厅的菜单包含多个选项,如前菜、主菜、饮料和甜点,顾客可以根据他们的喜好和饥饿程度来定制自己的菜单。

汽车制造:每个车型具有不同的配置,如引擎类型、座位数量和外观,可以为每个车型创建对应的车辆建造者类。

电脑组装:每个电脑配置由不同的组件构成,如处理器、内存、硬盘和操作系统,客户可以根据自己的需求来定制电脑的配置。

假设要组装一辆汽车,可以设计一个汽车建造者类,它包含setEngine()、setWheels()、setInterior()等方法来添加汽车的各个组件,构建汽车的样例代码如下:

CarBuilder builder = new CarBuilder();
builder.setEngine("V6");
builder.setWheels(4);
builder.setLeatherInterior();

Car myCar = builder.build();

二,建造者模式的结构

建造者模式主要包含以下组件:

1.产品对象(Product):

需要被构建的复杂对象,它通常包含多个组件,每个组件都有自己的属性和行为。具体建造者负责创建和配置产品对象的各个组件。

2.建造者(Builder):

定义了构建产品对象的公共接口,它包含了创建产品对象各部分组件的抽象方法,以及返回产品对象的方法。

3.具体建造者(ConcreteBuilder):

包含了对Builder接口的具体实现,它通常有一个成员变量用于保存最终构建的产品对象。

4.指挥者(Director):

负责管理构建产品的全过程,它通常会接收一个具体建造者的实例作为参数,根据特定的构建顺序来构建产品。

组件之间的工作步骤如下:

1.Director收到构建请求后,根据具体建造者调用具体建造者的方法。

2.具体建造者根据构建请求创建新的产品对象,并使用一系列的方法设置产品各个组件的属性。

3.构建完成后,具体建造者将构建好的产品对象返回给Director。

4.Director可以选择从具体建造者获取产品对象,并执行进一步的操作,例如输出结果、序列化等。

对应UML类图:

三,建造者模式代码样例

Demo1:没有Director参与

#include <iostream>
#include <string>

// Product
class Product {
public:
    void setPart1(int part1) {
        part1_ = part1;
    }
    void setPart2(const std::string& part2) {
        part2_ = part2;
    }
    void show() {
        std::cout << "Part 1: "
                  << part1_
                  << "\nPart 2: "
                  << part2_ << std::endl;
    }
private:
    int part1_;
    std::string part2_;
};

// Builder
class Builder {
public:
    virtual void buildPart1() = 0;
    virtual void buildPart2() = 0;
    virtual Product getResult() = 0;
};

// Concrete Builder
class ConcreteBuilder : public Builder {
public:
    ConcreteBuilder() {
        product_ = new Product();
    }
    void buildPart1() override {
        product_->setPart1(30);
    }
    void buildPart2() override {
        product_->setPart2("Part2 !");
    }
    Product getResult() override {
        return *product_;
    }
private:
    Product* product_;
};

int main() {
    ConcreteBuilder builder;
    builder.buildPart1();
    builder.buildPart2();

    Product product = builder.getResult();
    product.show();

    return 0;
}

运行结果:

Part 1: 30
Part 2: Part2 !

Demo2:包含Director

#include <iostream>
#include <string>

// 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() {
        std::cout << "Part A: " << partA_ << std::endl;
        std::cout << "Part B: " << partB_ << std::endl;
        std::cout << "Part C: " << partC_ << std::endl;
    }
private:
    std::string partA_;
    std::string partB_;
    std::string partC_;
};

// Builder
class Builder {
public:
    virtual void buildPartA() = 0;
    virtual void buildPartB() = 0;
    virtual void buildPartC() = 0;
    virtual Product* getProduct() = 0;
};

// Concrete Builder
class ConcreteBuilder : public Builder {
public:
    ConcreteBuilder() {
        product_ = new Product();
    }
    void buildPartA() {
        product_->setPartA("Part A");
    }
    void buildPartB() {
        product_->setPartB("Part B");
    }
    void buildPartC() {
        product_->setPartC("Part C");
    }
    Product* getProduct() {
        return product_;
    }
private:
    Product* product_;
};

// Director
class Director {
public:
    void construct(Builder* builder) {
        builder->buildPartA();
        builder->buildPartB();
        builder->buildPartC();
    }
};

int main() {
    ConcreteBuilder builder;
    Director director;
    director.construct(&builder);
    Product* product = builder.getProduct();
    product->show();
    delete product;
    return 0;
}

运行结果:

Part A: Part A
Part B: Part B
Part C: Part C

四,建造者模式的应用场景

图形用户界面开发:比如Windows操作系统的控件库,可以通过建造者自定义组合各种控件的位置、大小和样式。

XML文档生成器:通过建造者可以逐步构建复杂的XML文档结构,控制每个元素的添加顺序和属性设置。

数据库调度:可以用建造者提供一系列选项,如驱动程序、主机地址、端口等,按配置连接指定的数据库。

网络编程:可以根据需求动态配置HTTP、FTP或其他请求的细节,如URL、header信息、参数等。

五,建造者模式的优缺点

建造者模式的优点:

无需修改原有代码结构,可以灵活配置构建的过程。

封装性好,客户只需要关注如何组合,不需要关注组合的实现细节。

更加精细地控制对象的构建过程。

易于测试,由于建造过程是清晰的,所以更容易编写单元测试用例进行测试。

建造者模式的缺点:

对象创建过程的分解,使得代码量很大,且可读性差。

当对象的属性和组件特别多时,构建对象的代码会很复杂。

如果在对象初始化过程中就确定了所有属性,容易导致过早绑定。

六,代码实战

Demo1:模拟汉堡的制作过程

#include <iostream>
#include <string>
class Burger {
public:
    void setBurgerType(const std::string& type) {
        m_burgerType = type;
    }
    void setCheese(const bool cheese) {
        m_cheese = cheese;
    }
    void setPickles(const bool pickles) {
        m_pickles = pickles;
    }
    void setMayonnaise(const bool mayonnaise) {
        m_mayonnaise = mayonnaise;
    }
    std::string getBurgerType() const {
        return m_burgerType;
    }
    std::string getCheese() const {
        return m_cheese ? "Cheese" : "No cheese";
    }
    std::string getPickles() const {
        return m_pickles ? "Pickles" : "No pickles";
    }
    std::string getMayonnaise() const {
        return m_mayonnaise ? "Mayonnaise" : "No mayonnaise";
    }
private:
    std::string m_burgerType;
    bool m_cheese;
    bool m_pickles;
    bool m_mayonnaise;
};
class BurgerBuilder {
public:
    BurgerBuilder() {
        m_burger = new Burger();
    }
    BurgerBuilder* setBurgerType(const std::string& type) {
        m_burger->setBurgerType(type);
        return this;
    }
    BurgerBuilder* addCheese() {
        m_burger->setCheese(true);
        return this;
    }
    BurgerBuilder* addPickles() {
        m_burger->setPickles(true);
        return this;
    }
    BurgerBuilder* addMayonnaise() {
        m_burger->setMayonnaise(true);
        return this;
    }
    Burger* build() {
        return m_burger;
    }
private:
    Burger* m_burger;
};
int main() {
    Burger* burger = BurgerBuilder()
        .setBurgerType("Chicken Burger")
        ->addCheese()
        ->addPickles()
        ->build();
    std::cout << "Burger Type: " << burger->getBurgerType() << std::endl;
    std::cout << "Cheese: " << burger->getCheese() << std::endl;
    std::cout << "Pickles: " << burger->getPickles() << std::endl;
    std::cout << "Mayonnaise: " << burger->getMayonnaise() << std::endl;
    delete burger;
    return 0;
}

运行结果:

Burger Type: Chicken Burger
Cheese: Cheese
Pickles: Pickles
Mayonnaise: No mayonnaise

Demo2:模拟台式机的组装过程

#include <iostream>
#include <string>
using namespace std;

// Product
class Computer {
public:
       void setCPU(const std::string& cpu) {
              cpu_ = cpu;
       }
       void setRAM(const std::string& ram) {
              ram_ = ram;
       }
       void setStorage(const std::string& storage) {
              storage_ = storage;
       }
       void displayInfo() const {
              std::cout << "Computer Configuration:"
                      << "\nCPU: " << cpu_
                      << "\nRAM: " << ram_
                      << "\nStorage: " << storage_ << "\n\n";
       }
private:
       string cpu_;
       string ram_;
       string storage_;
};

// Builder
class Builder {
public:
       virtual void buildCPU() = 0;
       virtual void buildRAM() = 0;
       virtual void buildStorage() = 0;
       virtual Computer getResult() = 0;
};

// ConcreteBuilder
class GamingComputerBuilder : public Builder {
private:
       Computer computer_;
public:
       void buildCPU() override {
              computer_.setCPU("Gaming CPU");
       }
       void buildRAM() override {
              computer_.setRAM("16GB DDR4");
       }
       void buildStorage() override {
              computer_.setStorage("1TB SSD");
       }
       Computer getResult() override {
              return computer_;
       }
};

// Director
class ComputerDirector {
public:
       void construct(Builder& builder) {
              builder.buildCPU();
              builder.buildRAM();
              builder.buildStorage();
       }
};

int main() {
       GamingComputerBuilder gamingBuilder;
       ComputerDirector director;
       director.construct(gamingBuilder);
       Computer gamingComputer = gamingBuilder.getResult();
       gamingComputer.displayInfo();
       return 0;
}

运行结果:

Computer Configuration:
CPU: Gaming CPU
RAM: 16GB DDR4
Storage: 1TB SSD

七,参考阅读

https://gist.github.com/pazdera/1121152

https://www.geeksforgeeks.org/builder-design-pattern/

https://www.tutorialspoint.com/design_pattern/builder_pattern.html

https://rust-unofficial.github.io/patterns/patterns/creational/builder.html

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

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

相关文章

网络安全架构师

网络安全架构师负责构建全面的安全框架&#xff0c;以保护组织的数字资产免受侵害&#xff0c;确保组织在数字化转型的同时维持强大的安全防护。 摩根大通的网络安全运营副总裁兼安全架构总监Lester Nichols强调&#xff0c;成为网络安全架构师对现代企业至关重要&#xff0c;…

单向链表之创建,插入,输出(上)

文章目录 &#x1f34a;自我介绍&#x1f34a;创建&#x1f34a;插入&#x1f34a;输出 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家好&#xff0c;我是小珑也要…

VMware Fusion虚拟机Mac版 安装Ubuntu操作系统教程

Mac分享吧 文章目录 下载镜像地址&#xff1a;[www.macfxb.cn](http://www.macfxb.cn)一、CentOS安装完成&#xff0c;软件打开效果二、Mac中安装Ubuntu虚拟机1️⃣&#xff1a;下载镜像2️⃣&#xff1a;创建虚拟机3️⃣&#xff1a;虚拟机设置4️⃣&#xff1a;虚拟机安装5️…

计算机三级 - 数据库技术 - 第十四章 数据仓库与数据挖掘 笔记

第十四章 数据仓库与数据挖掘 内容提要&#xff1a; 了解数据仓库相关技术了解数据仓库的设计、建造、运行及维护了解OLAP及多维数据模型了解数据挖掘技术 决策支持系统(DSS)&#xff1a;综合利用大量数据有机组合众多模型(数学模型和数据处理模型)&#xff0c;通过人机交互&a…

uniapp 端开发 echarts 树结构图

实现效果 &#xff1a; 1. 在uniapp 中写echarts 树结构图需要使用 <script module"echarts" lang"renderjs"> 否则会无法显示echarts 图形 rebderjs 代码 引入了 /static/echarts.min.js 是在 ECharts 在线构建 定制你的echarts <te…

001 RabbitMQ入门及安装

RabbitMQ入门及安装 文章目录 RabbitMQ入门及安装1.介绍1.AMQP和JMS2.目前主流的消息队列 2.安装1.Linux安装1.1 安装erlang1.2 RabbitMQ安装 2.Docker安装 3.核心组件 1.介绍 RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff08;亦…

嵌入式音视频开发:探索多领域的融合与创新

摘要&#xff1a; 本文深入探讨了嵌入式音视频开发领域。从嵌入式系统的基础概念入手&#xff0c;阐述了其在音视频领域的独特地位。详细介绍了嵌入式音视频开发中涉及的硬件组件&#xff0c;如处理器、编解码器、存储设备等。分析了音视频编解码技术&#xff0c;包括常见的编解…

空间数据库概述

空间数据库简介 空间数据库是 地理信息系统 在计算机物理存储介质中存储的&#xff0c;与GIS应用相关的地理空间数据的总和。一般以一系列特定结构的文件形式组织后存储在介质上。 空间数据库的特点 可以存储、处理空间数据相比普通数据库提供更多、更复杂的数据类型以及更多…

[SWPU2019]Web1 超详细教程

老规矩先看源码&#xff0c;没找到啥提示&#xff0c;后面就是登录口对抗 弱口令试了几个不行&#xff0c;就注册了个账户登录进去 可以发布广告&#xff0c;能造成xss&#xff0c;但是没啥用啊感觉 查看广告信息的时候&#xff0c;注意到url当中存在id参数&#xff0c;可能存…

Leetcode面试经典150题-134.加油站

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {/**如果只有一个加油站&#xff0c;那它本来就在那个为止&#xff0c;0就是它的编号?但是这只是你的想象&#xff0c;题目有个变态规定&#xff0c;自…

【linux】进程控制(2)

3. 进程等待 1. 是什么 通过系统调用 wait/waitpid 对子进程的退出状态进行检测和回收的功能 2. 为什么 僵尸进程无法杀死&#xff0c;通过进程等待来杀掉它&#xff0c;进而解决内存泄漏的问题 &#xff08;一&#xff09;进程等待的方法 a. wait : 代码 wait : 等待任意一…

解锁SAP数据的潜力:SNP Glue与SAP Datasphere的协同作用

在各种文章中&#xff0c;我们研究了客户如何利用SNP Glue与基于云的数据仓库和数据湖相结合&#xff0c;以充分利用其SAP数据。SNP Glue 通过高性能集成解决方案帮助客户解锁 SAP 数据孤岛。例如&#xff0c;可以使用SNP Glue先进的增量捕获&#xff08;CDC&#xff09;近乎实…

【Linux 报错】Ubuntu 20.04.5 LTS报错:“E: Unable to locate package xx”

问题描述&#xff1a; 在使用 &#xff08;Ubuntu 20.04.5 LTS&#xff09;学习 Linux 时&#xff0c;想要安装 tree 命令&#xff0c;出现下面的报错&#xff1a; rootiZwz9asjf1ddlt6fy1ebqpZ:~# apt install tree Reading package lists... Done Building dependency tree…

蓝光3D扫描仪用于小尺寸精密注塑零件三维检测

在现代精密制造领域&#xff0c;微小型零件的加工和检测依然极具挑战。无论是微型机械零件、电子元器件&#xff0c;汽车注塑件&#xff0c;还是高端医疗器械部件&#xff0c;制造商都必须确保零件尺寸符合设计要求。传统的检测方法已无法满足日益严苛的要求&#xff0c;企业亟…

828华为云征文 | Flexus X的力量,驱动Halo博客在云端飞驰

前言 华为云Flexus云服务器 X实例&#xff0c;以卓越性能与灵活配置&#xff0c;为Halo博客搭建起梦想的云端舞台。在这个828企业上云节节日里&#xff0c;华为云Flexus云服务器 X实例不仅提供了稳定高效的运行环境&#xff0c;更助力Halo博客实现内容创作的无限可能。无论是流…

240912-通过Ollama实现网站知识总结

A. 最终效果 B. 准备工作 报错: USER_AGENT environment variable not set, consider setting it to identify your requests.-CSDN博客 C. 完整代码 # https://coreyclip.github.io/Ollama-Web-Summaries/import os os.environ[USER_AGENT] Mozilla/5.0 (Windows NT 10.…

docker安装部署Canal-监听mysql

文章目录 安装和配置Canal1.开启MySQL主从1.1.开启binlog1.2.设置用户权限 2.安装Canal2.1.创建网络2.3.安装Canal 遇到的问题 安装和配置Canal 下面我们就开启mysql的主从同步机制&#xff0c;让Canal来模拟salve 1.开启MySQL主从 Canal是基于MySQL的主从同步功能&#xff…

cheat:在终端中,在线查询Linux命令

cheat.sh 是一个命令查询网站&#xff0c;在终端中也能够使用。特点是返回简单易懂的代码示例和注解&#xff0c;可以帮助用户快速了解命令的使用方法。 ​​ 1.语法 curl cheat.sh/command2.示例 查询 ls 命令的用法 curl cheat.sh/ls查询 chmod 命令的用法 curl cheat.…

sqlite在Windows环境下安装、使用、node.js连接

sqlite在Windows环境下安装、使用、node.js连接 前言&#xff1a;2024年9月10日 1. 下载安装 sqlite 的安装非常简单 去官网下载对应压缩包 将两个压缩包解压&#xff0c;并将解压出来的文件放在同一目录下 将上面的目录路径配置到环境变量 path 中 2. 执行 sql sqlite …

Day7 | Java框架 | SpringMVC

Day7 | Java框架 | SpringMVC SpringMVC简介SpringMVC 概述入门案例入门案例工作流程分析Controller 加载控制与业务bean加载控制&#xff08;SpringMVC & Spring&#xff09;PostMan 请求与响应请求映射路径请求方式&#xff08;不同类型的请求参数&#xff09;&#xff1…