突破编程_C++_设计模式(建造者模式)

1 建造者模式的概念

建造者模式(Builder Pattern)是一种创建型设计模式,也被称为生成器模式。它的核心思想是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

在建造者模式中,通常包括以下几个角色:

(1)Builder: 这是一个抽象接口,定义了产品对象的各个组成成分的建造。它规定了要实现复杂对象的哪些部分的创建,但并不涉及具体的对象部件的创建。
(2)ConcreteBuilder: 这是实现了Builder接口的具体类,它针对不同的商业逻辑,具体化了复杂对象的各部分的创建。在建造过程完成后,它提供产品的实例。
(3)Director: 这是一个指挥者角色,它调用具体建造者来创建复杂对象的各个部分。在指导者中,不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
(4)Product: 这是最终要创建的复杂对象。

建造者模式允许用户只通过指定复杂对象的类型和内容来构建对象,而不需要知道内部的具体构建细节。这种模式特别适用于构建具有多个组成部分的复杂对象,且这些组成部分的构建过程可能会因具体需求而有所不同的情况。通过建造者模式,可以使得同样的构建过程能够创建出不同的产品表示,提高了系统的灵活性和可扩展性。

1.1 建造者模式的应用场景

建造者模式通常适用于以下应用场景:

(1)对象结构复杂: 当需要创建的对象具有复杂的内部结构,包含多个组件或属性时,可以使用建造者模式来构建这些对象。通过将构建过程分解为多个步骤,可以更加清晰地管理和控制对象的创建过程。
(2)创建流程固定: 当对象的创建流程是固定的,即无论创建多少个对象,其构建步骤都是相同的时候,可以使用建造者模式。通过将这些步骤封装在建造者类中,可以确保每次创建对象时都遵循相同的流程。
(3)需要控制创建过程: 当需要更加灵活地控制对象的创建过程,例如根据用户输入或运行时条件来决定对象的某些属性时,可以使用建造者模式。通过在指挥者类中引入逻辑来控制对象的创建,可以实现更加灵活的构建过程。
(4)代码易于阅读和维护: 当需要创建的对象具有大量的参数或配置选项时,使用建造者模式可以将这些参数和选项分组并封装在不同的建造者类中,从而减少构造函数的复杂度,使代码更加易读和易于维护。

在实际应用中,建造者模式常用于构建具有多个组件或属性的复杂对象,如UI界面、配置文件、数据库查询结果等。通过使用建造者模式,可以更加清晰地组织代码,提高代码的可读性和可维护性,同时降低对象创建的复杂性。

1.2 建造者模式的优点和缺点

建造者模式的优点主要包括:

(1)封装性好: 建造者模式将对象的构建与它的表示分离,使得客户端不必知道产品内部组成的细节,隐藏了产品的内部实现细节,提供了更好的封装性。
(2)扩展性好: 由于具体的建造者是相互独立的,因此易于扩展。如果需要增加新的部件或修改现有部件的创建方式,只需要增加或修改相应的建造者类,而不会影响其他已构建的部件和客户端代码。
(3)控制细节风险: 建造者模式允许对创建过程逐步细化,而不对其他模块产生任何影响,便于控制细节风险。客户端只需要指定需要构建的对象类型和内容,而不需要了解具体的构建细节,从而降低了客户端代码的复杂性。

然而,建造者模式也存在一些缺点:

(1)使用范围受限: 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似。如果产品之间的差异性很大,例如很多组成部分都不相同,不适合使用建造者模式,因此其使用范围受到一定的限制。
(2)可能导致系统庞大: 如果产品的内部变化复杂,可能需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。这会增加系统的理解难度和运行成本,因为需要维护大量的建造者类。

综上所述,建造者模式在创建具有复杂内部结构和多个组件的对象时非常有用,可以提供良好的封装性、扩展性和对细节的控制。然而,它也有一些限制,特别是在产品差异性大或内部变化复杂的情况下。因此,在使用建造者模式时需要权衡其优点和缺点,并根据具体的应用场景做出决策。

2 建造者模式的实现步骤

本章节使用一个建造房子的样例来讲解建造者模式的实现步骤。

2.1 定义产品(Product)类

首先,定义 Product 类,它表示最终要构建的对象。在本章节的例子中,构建一个 House 类:

#include <iostream>  
#include <memory>  
#include <string>  class House 
{
public:void setWalls(const std::string& walls) {this->walls = walls;}void setRoof(const std::string& roof) {this->roof = roof;}void setFloors(const std::string& floors) {this->floors = floors;}void showHouseDetails() const {std::cout << "Walls: " << walls << std::endl;std::cout << "Roof: " << roof << std::endl;std::cout << "Floors: " << floors << std::endl;}private:std::string walls;std::string roof;std::string floors;
};

2.2 定义抽象建造者(Builder)接口

接下来,定义一个 Builder 抽象接口,它声明了构建 House 对象所需的方法:

class HouseBuilder 
{
public:virtual ~HouseBuilder() = default;virtual void buildWalls() = 0;virtual void buildRoof() = 0;virtual void buildFloors() = 0;virtual std::shared_ptr<House> getHouse() = 0;
};

2.3 定义具体建造者(ConcreteBuilder)类

然后,创建实现 HouseBuilder 接口的 ConcreteBuilder 类。这个类将包含构建 House 对象所需的具体实现:

class ConcreteHouseBuilder : public HouseBuilder 
{
public:ConcreteHouseBuilder() : house(std::make_shared<House>()) {}void buildWalls() override {house->setWalls("Concrete walls");}void buildRoof() override {house->setRoof("Concrete roof");}void buildFloors() override {house->setFloors("Concrete floors");}std::shared_ptr<House> getHouse() override{return std::move(house);}private:std::shared_ptr<House> house;
};

2.4 定义指挥者(Director)类

接下来,创建一个 Director 类,它负责指挥 Builder 对象来构建 Product 对象:

class HouseDirector 
{
public:HouseDirector(std::shared_ptr<HouseBuilder> builder) : builder(builder) {}void constructHouse() {builder->buildWalls();builder->buildRoof();builder->buildFloors();}std::shared_ptr<House> getHouse(){return builder->getHouse();}private:std::shared_ptr<HouseBuilder> builder;};

2.5 客户端使用

最后,在 main 函数中,使用这些类来构建 House 对象:

int main() 
{// 创建具体建造者对象  auto builder = std::make_shared<ConcreteHouseBuilder>();// 创建指挥者对象,并将建造者传递给指挥者  HouseDirector director(builder);// 通过指挥者构建产品  director.constructHouse();// 获取并显示构建好的产品  auto house = director.getHouse();house->showHouseDetails();return 0;
}

上面代码的输出为:

Walls: Concrete walls
Roof: Concrete roof
Floors: Concrete floors

在上面代码中,使用 std::make_shared 来创建 ConcreteHouseBuilder 对象,并将其传递给 HouseDirector 。HouseDirector 通过调用 concreteHouseBuilder 的方法逐步构建了一个 House 对象,并通过 getHouse 方法返回了 House 对象的所有权。最后,获取这个构建好的 House 对象,并显示其对象细节。

3 建造者模式的案例解析

3.1 对象结构复杂场景下使用建造者模式

如下的样例将展示如何使用建造者模式来构建一个 Computer 对象,其中包含 Processor 和 Memory 两个子组件(为了简化代码,实际一个电脑的子组件会很多)。

首先,定义各个子组件以及 Computer 类:

#include <iostream>  
#include <memory>  
#include <string>  // 子组件类  
class Processor 
{
public:void setSpeed(int speed) { m_speed = speed; }void setCores(int cores) { m_cores = cores; }void showDetails() const {std::cout << "Processor: " << m_speed << " MHz, " << m_cores << " cores" << std::endl;}private:int m_speed;int m_cores;
};class Memory 
{
public:void setSize(int size) { m_size = size; }void setType(const std::string& type) { m_type = type; }void showDetails() const {std::cout << "Memory: " << m_size << " GB, " << m_type << " RAM" << std::endl;}private:int m_size;std::string m_type;
};// 产品类  
class Computer {
public:void setProcessor(std::shared_ptr<Processor> processor) { m_processor = processor; }void setMemory(std::shared_ptr<Memory> memory) { m_memory = memory; }void showDetails() const {m_processor->showDetails();m_memory->showDetails();}private:std::shared_ptr<Processor> m_processor;std::shared_ptr<Memory> m_memory;
};

接下来,定义抽象建造者接口和具体的建造者类:

// 产品类  
class Computer {
public:void setProcessor(std::shared_ptr<Processor> processor) { m_processor = processor; }void setMemory(std::shared_ptr<Memory> memory) { m_memory = memory; }void showDetails() const {m_processor->showDetails();m_memory->showDetails();}private:std::shared_ptr<Processor> m_processor;std::shared_ptr<Memory> m_memory;
};// 抽象建造者接口  
class ComputerBuilder 
{
public:virtual ~ComputerBuilder() = default;virtual void buildProcessor() = 0;virtual void buildMemory() = 0;virtual std::shared_ptr<Computer> getComputer() = 0;
};// 具体建造者类  
class GamingComputerBuilder : public ComputerBuilder 
{
public:GamingComputerBuilder() : m_computer(std::make_shared<Computer>()) {m_processor = std::make_shared<Processor>();m_memory = std::make_shared<Memory>();}void buildProcessor() override {m_processor->setSpeed(3500);m_processor->setCores(6);}void buildMemory() override {m_memory->setSize(16);m_memory->setType("DDR4");}std::shared_ptr<Computer> getComputer() override {m_computer->setProcessor(m_processor);m_computer->setMemory(m_memory);return m_computer;}private:std::shared_ptr<Computer> m_computer;std::shared_ptr<Processor> m_processor;std::shared_ptr<Memory> m_memory;
};

然后,定义 Director 类,负责指导 Builder 对象如何构建最终的产品:

class Director 
{
public:Director(std::shared_ptr<ComputerBuilder> builder) : m_builder(builder) {}void constructComputer() {m_builder->buildProcessor();m_builder->buildMemory();}std::shared_ptr<Computer> getComputer() {return m_builder->getComputer();}private:std::shared_ptr<ComputerBuilder> m_builder;
};

最后,在 main 函数中使用 Director 和 GamingComputerBuilder 来构建一个 Computer 对象:

int main() 
{// 创建具体的建造者对象  std::shared_ptr<ComputerBuilder> builder = std::make_shared<GamingComputerBuilder>();// 创建导演对象,并将建造者对象传递给它  Director director(builder);// 指导构建过程  director.constructComputer();// 获取构建好的产品  std::shared_ptr<Computer> computer = director.getComputer();// 展示产品详情  computer->showDetails();return 0;
}

上面代码的输出为:

Processor: 3500 MHz, 6 cores
Memory: 16 GB, DDR4 RAM

3.2 对象结构复杂场景下使用建造者模式

在创建流程固定的场景下,可以使用一个简单的 Builder 类来封装一个固定流程的构建过程。这种场景下,Builder 类会提供一系列的方法来逐步构建对象,并最终提供一个方法来获取构建好的对象。客户端代码则直接调用 Builder 的方法来构建对象。
如下为样例代码:

#include <iostream>  
#include <memory>  
#include <string>  // 产品类  
class Product 
{
public:void show() const {std::cout << "Product built with parts: " << partA << ", " << partB << ", " << partC << std::endl;}public:std::string partA;std::string partB;std::string partC;
};// 建造者类  
class Builder 
{
public:Builder() { m_product = std::make_shared<Product>(); }// 初始化产品  void setPartA(const std::string& partA) { m_product->partA = partA; }void setPartB(const std::string& partB) { m_product->partB = partB; }void setPartC(const std::string& partC) { m_product->partC = partC; }// 构建并返回产品  std::shared_ptr<Product> build() {// 在这里可以添加一些额外的构建逻辑return m_product;}private:std::shared_ptr<Product> m_product;
};int main() 
{// 创建建造者对象  Builder builder;// 通过建造者设置产品的各个部分  builder.setPartA("Part A content");builder.setPartB("Part B content");builder.setPartC("Part C content");// 构建并获取产品  auto product = builder.build();// 展示产品  product->show();return 0;
}

上面代码的输出为:

Product built with parts: Part A content, Part B content, Part C content

在上面代码中,Product 类是一个简单的产品类,包含三个私有成员变量。Builder 类封装了 Product 对象的构建过程,它提供了三个方法来设置产品的各个部分,以及一个 Build 方法来构建并返回产品对象。

在 main 函数中,客户端代码创建了 Builder 对象,并通过调用 setPartA、setPartB 和 setPartC 方法来设置产品的各个部分。然后,调用 Build 方法来构建产品对象,并存储在 std::shared_ptr 中。最后,调用Show方法来展示构建好的产品。

上面代码展示了如何在创建流程固定的情况下使用建造者模式。Builder 类确保了产品总是按照相同的步骤和顺序被构建,而客户端代码则不需要了解具体的构建细节。这有助于保持代码的清晰和易于维护。

4 建造者模式与工厂模式的比较

建造者模式和工厂模式都是面向对象设计模式中常用的创建型模式,它们的主要区别在于关注点、对象创建过程以及复杂度。

关注点: 工厂模式主要关注对象的创建,而建造者模式不仅关注对象的创建,还关注对象的组成部分以及这些部分的构建顺序。
对象创建过程: 工厂模式通常提供一个统一的接口来创建对象,而不需要知道具体创建对象的类。而建造者模式则更加关注对象的构建过程,它允许用户逐步添加对象的各个部分,并控制这些部分的构建顺序。
复杂度: 工厂模式通常用于创建简单对象,而建造者模式更适合用于创建复杂对象。建造者模式允许用户将复杂对象的构建过程分解为多个步骤,每个步骤只关注对象的一个或几个部分,从而降低了构建过程的复杂度。

总的来说,工厂模式和建造者模式都是用于创建对象的模式,但它们在关注点、对象创建过程以及复杂度上有所不同。选择哪种模式取决于具体的应用场景和需求。

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

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

相关文章

MySQL进阶:MySQL事务、并发事务问题及隔离级别

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习、 &#x1f30c;上期文章&#xff1a;MySQL进阶&#xff1a;视图&&存储过程&&存储函数&&触发器 &#x1f4da;订阅专栏&#xff1a;MySQL进…

Docker Machine windows系统下 安装

如果你是 Windows 平台&#xff0c;可以使用 Git BASH&#xff0c;并输入以下命令&#xff1a; basehttps://github.com/docker/machine/releases/download/v0.16.0 &&mkdir -p "$HOME/bin" &&curl -L $base/docker-machine-Windows-x86_64.exe >…

点燃技能火花:探索PyTorch学习网站,开启AI编程之旅!

介绍&#xff1a;PyTorch是一个开源的Python机器学习库&#xff0c;它基于Torch&#xff0c;专为深度学习和科学计算而设计&#xff0c;特别适合于自然语言处理等应用程序。以下是对PyTorch的详细介绍&#xff1a; 历史背景&#xff1a;PyTorch起源于Torch&#xff0c;一个用于…

【真机Bug】异步加载资源未完成访问单例导致资源创建失败

1.错误表现描述 抽卡时&#xff0c;10抽展示界面为A。抽取内容可能是整卡或者碎片&#xff0c;抽到整卡&#xff0c;会有立绘展示和点击详情的按钮。点击详情后出现详情页B。【此时界面A预制体被销毁&#xff0c;卡片数据进入数据缓存池】点击页面B的返回按钮&#xff0c;单例…

C++——模版

前言&#xff1a;哈喽小伙伴们好久不见&#xff0c;这是2024年的第一篇博文&#xff0c;我们将继续C的学习&#xff0c;今天这篇文章&#xff0c;我们来习一下——模版。 目录 一.什么是模版 二.模版分类 1.函数模版 2.类模板 总结 一.什么是模版 说起模版&#xff0c;我们…

线索二叉树

线索二叉树即从前、中、后序三种遍历中其中一种来看&#xff0c;树中的左右孩子都不会是空着的&#xff0c;都会指向对应的前驱和后驱。 以中序遍历为例&#xff0c;二叉树线索化过程如下&#xff1a; 先是树的结构 typedef struct ThreadNode{Elemetype data;struct ThreadNo…

微服务面试题之套路一

面试题 一、你的项目是从SpringBoot演进到微服务架构的&#xff0c;你在此过程中有调研过哪些技术&#xff0c;怎么调研落地的? 微服务通信框架&#xff1a; 需要选择适合项目的微服务通信框架&#xff0c;如Dubbo、Spring Cloud或gRPC Feign RestTemplate 等。调研方式可以是…

高性能通信之Netty

一, 同步IO(BIO)模型的架构 一般针对性能不高的情况下可以使用. 二,异步IO(NIO)模型的架构 多路复用(epoll模型):

【LeetCode:124. 二叉树中的最大路径和 + 二叉树+递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

前端开发人员如何做好SEO

前端开发人员如何做好SEO SEO工作不仅限于专业人员。前端开发者也可以在日常开发中实施一些代码层面的SEO优化。 以下是一些前端常用的SEO方法&#xff1a; 设置合理的title、keywords、description title、keywords、description对SEO至关重要&#xff0c;需贴合页面内容编…

Codeforces Round 931 (Div. 2) (A~B)

比赛&#xff1a;Codeforces Round 931 (Div. 2) (A~B) 目录&#xff1a;A B A题&#xff1a;Too Min Too Max 标签: 构造算法&#xff08;constructive algorithms&#xff09;贪心&#xff08;greedy&#xff09;数学&#xff08;math&#xff09; 题目大意 对数组 a 找到…

【力扣hot100】刷题笔记Day19

前言 回溯回溯回溯&#xff01;早上整理档案竟然用了桶排序&#xff0c;不愧是算法狂魔们 79. 单词搜索 - 力扣&#xff08;LeetCode&#xff09; DFS class Solution:def exist(self, board: List[List[str]], word: str) -> bool:m, n len(board), len(board[0])# used…

mysql timestamp转换为datetime

MySQL timestamp转换为datetime的方法 1. 流程概述 在MySQL中&#xff0c;timestamp和datetime是两种不同的数据类型。timestamp存储了日期和时间&#xff0c;并且会自动更新&#xff0c;可以用于记录数据的创建和修改时间。datetime则是一个固定的日期和时间&#xff0c;不会自…

谈谈高并发系统的设计方法论

谈谈高并发系统的设计方法论 何为高并发系统&#xff1f;什么是并发&#xff08;Conurrent&#xff09;&#xff1f;什么是高并发&#xff08;Hight Concurrnet&#xff09;&#xff1f;高并发的衡量指标有哪些&#xff1f; 实现高并发系统的两大板块高并发系统应用程序侧的设计…

腾讯云学生服务器使用教程_申请腾讯云学生机详细流程

2024年腾讯云学生服务器优惠活动「云校园」&#xff0c;学生服务器优惠价格&#xff1a;轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G配置842.4元一年&…

还在用Jenkins?快来试试这款简而轻的自动部署软件!

最近发现了一个比 Jenkins 使用更简单的项目构建和部署工具&#xff0c;完全可以满足个人以及一些小企业的需求&#xff0c;分享一下。 Jpom 是一款 Java 开发的简单轻量的低侵入式在线构建、自动部署、日常运维、项目监控软件。 日常开发中&#xff0c;Jpom 可以解决下面这些…

Nginx的多线程支持探究

文章中心思想: Nginx本身并不直接支持多线程处理模型。它采用的是基于事件驱动的单线程或多进程架构,而非多线程模型。然而,通过Nginx的模块和第三方扩展,可以实现类似多线程的并发处理效果。 详细说明: Nginx,作为一款高性能的Web服务器和反向代理服务器,其架构和并发…

章节二、three.js开发入门与调试设置02;

一、轨道控制器查看物体&#xff1b; 1、基本概念 轨道控制器&#xff08;OrbitControls&#xff09;可以使得相机围绕目标进行轨道运动&#xff1b; 2、代码样例 // 七、创建轨道控制器&#xff08;相机围绕着物体捕捉视角&#xff09; const controls new OrbitControls(c…

吴恩达机器学习全课程笔记第五篇

目录 前言 P80-P85 添加数据 迁移学习 机器学习项目的完整周期 公平、偏见与伦理 P86-P95 倾斜数据集的误差指标 决策树模型 测量纯度 选择拆分方式增益 使用分类特征的一种独热编码 连续的有价值特征 回归树 前言 这是吴恩达机器学习笔记的第五篇&#xff0c…

《2023跨境电商投诉大数据报告》发布|亚马逊 天猫国际 考拉海购 敦煌网 阿里巴巴

2023年&#xff0c;跨境电商API接口天猫国际、京东国际和抖音全球购以其强大的品牌影响力和市场占有率&#xff0c;稳坐行业前三的位置。同时&#xff0c;各大跨境电商平台消费纠纷问题层出不穷。依据国内知名网络消费纠纷调解平台“电诉宝”&#xff08;315.100EC.CN&#xff…