04创建型设计模式——建造者模式

news2024/9/22 13:42:02

一、建造者模式简介

建造者模式(Builder Pattern)又被称为生成器模式。它旨在构建一个复杂对象的各个部分,而不需要指定该对象的具体类。该模式特别适用于对象的构建过程复杂且需要多个步骤的情况。建造者模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。

建造者模式适用于:当一个对象的构建比较复杂,将一个对象的构建(?)和对象的表示(?)进行分离的情况

  1. 分离构建和表示
    建造者模式通过将复杂对象的构建过程与其表示分离开来,允许构建过程的变化不会影响到最终对象的表示。也就是说,构建者模式关注的是如何一步一步地构建一个对象,而不是最终对象是什么样的。

  2. 逐步构建
    该模式允许通过多个步骤(方法)来逐步构建对象,这些步骤可以是可选的或者是必需的。构建的顺序和内容可以被灵活控制。

GoF一书中对建造者模式的介绍

 二、建造者模式的用处

1. 复杂对象的构建

当一个对象的构建过程包含多个步骤或组件时,建造者模式可以帮助将这些步骤分开,从而使构建过程更加清晰和易于管理。例如,构建一个具有多种配置选项的复杂数据结构或图形用户界面(GUI)组件。

2. 构建过程的灵活性

建造者模式允许灵活地定制对象的创建过程,而无需修改对象的具体实现。例如,不同的建造者可以用于创建具有不同配置或特性的对象,而指挥者(Director)负责控制构建的步骤和顺序。

3. 解耦构建和表示

将对象的构建过程与表示分离,使得构建的过程和最终的对象类型可以独立变化。这种解耦使得系统更加灵活,易于扩展和维护。例如,你可以在不修改对象创建逻辑的情况下添加新的产品类型或更改产品的外观。

4. 支持逐步构建

对于需要逐步构建的对象,建造者模式可以逐步执行构建步骤。这样可以在构建过程中控制每个步骤的执行,并允许有选择地构建对象。例如,在构建复杂的报告或文档时,你可以按章节、段落等逐步添加内容。

5. 提高代码可读性和可维护性

通过将构建过程分解成多个清晰的步骤,建造者模式使得代码更加易读和易于维护。每个建造者只负责对象的一个方面的构建,使得构建过程更加模块化。

6. 支持复杂的构建逻辑

当对象的构建逻辑非常复杂,需要处理多种条件或选项时,建造者模式可以封装这些复杂的逻辑。这样,可以将构建逻辑集中在建造者类中,而客户端代码只需知道如何使用指挥者来创建对象

三、建造者模式的设计方法

 builder.cpp

#include <iostream>
#include <string>
#include <memory>

// 产品
class House {
public:
    void setDoor(const std::string& door) {
        this->door = door;
    }

    void setWall(const std::string& wall) {
        this->wall = wall;
    }

    void setWindow(const std::string& window) {
        this->window = window;
    }

    void setFloor(const std::string& floor) {
        this->floor = floor;
    }

    const std::string& getDoor() const {
        return this->door;
    }

    const std::string& getWall() const {
        return this->wall;
    }

    const std::string& getWindow() const {
        return this->window;
    }

    const std::string& getFloor() const {
        return this->floor;
    }

protected:
    std::string door;
    std::string wall;
    std::string window;
    std::string floor;
};

// 工程队
class Builder {
public:
    virtual ~Builder() {}

    virtual void buildWall() = 0;
    virtual void buildDoor() = 0;
    virtual void buildWindow() = 0;
    virtual void buildFloor() = 0;
    virtual std::shared_ptr<House> getHouse() = 0;
    virtual void viewHouse() const = 0; // 标记为 const
};

class VillaBuilder : public Builder {
public:
    VillaBuilder() : house(std::make_shared<House>()) {}

    void buildWall() override {
        house->setWall("别墅墙");
    }

    void buildDoor() override {
        house->setDoor("别墅门");
    }

    void buildWindow() override {
        house->setWindow("别墅窗户");
    }

    void buildFloor() override {
        house->setFloor("别墅地板");
    }

    std::shared_ptr<House> getHouse() override {
        return house;
    }

    void viewHouse() const override {
        std::cout << "这是一座好别墅,有" << house->getWall() << ", 有" << house->getWindow() << ", 有" << house->getDoor() << ", 有" << house->getFloor() << "!" << std::endl;
    }

private:
    std::shared_ptr<House> house;
};

class FlatBuilder : public Builder {
public:
    FlatBuilder() : house(std::make_shared<House>()) {}

    void buildWall() override {
        house->setWall("公寓墙");
    }

    void buildDoor() override {
        house->setDoor("公寓门");
    }

    void buildWindow() override {
        house->setWindow("公寓窗户");
    }

    void buildFloor() override {
        house->setFloor("公寓地板");
    }

    std::shared_ptr<House> getHouse() override {
        return house;
    }

    void viewHouse() const override {
        std::cout << "这是一座好公寓,有" << house->getWall() << ", 有" << house->getWindow() << ", 有" << house->getDoor() << ", 有" << house->getFloor() << "!" << std::endl;
    }

private:
    std::shared_ptr<House> house;
};

// 设计师
class Director {
public:
    Director(std::shared_ptr<Builder> builder) : builder(builder) {}

    void constructHouse() {
        builder->buildWall();   // 先建墙
        builder->buildWindow(); // 然后建窗户
        builder->buildDoor();   // 再建门
        builder->buildFloor();  // 最后建地板
    }

    void viewHouse() const {
        builder->viewHouse();
    }

private:
    std::shared_ptr<Builder> builder;
};

// 设计师请工程队按照图纸建造好房子(客户端)
void doWorking() {
    // 请一个建造别墅的工程队
    std::shared_ptr<Builder> builder = std::make_shared<VillaBuilder>();
    Director director(builder);
    director.constructHouse();
    director.viewHouse();

    // 请一个建造公寓的工程队
    builder = std::make_shared<FlatBuilder>();
    Director anotherDirector(builder);
    anotherDirector.constructHouse();
    anotherDirector.viewHouse();
}

int main() {
    // 开工
    doWorking();
    return 0;
}

运行效果

 

  1. 产品(Product)
    产品是最终构建出来的复杂对象,它包含多个组成部分和属性。产品类通常有多个子类,具体实现可以因业务需求而异。

  2. 建造者(Builder)
    建造者接口定义了构建产品的各个部分的方法。每个具体的建造者实现这些方法,按照特定的步骤来构建产品。

  3. 具体建造者(ConcreteBuilder)
    具体建造者实现了建造者接口,负责具体的构建步骤。这些步骤包括创建产品的不同部分,并在最后将产品返回。

  4. 指挥者(Director)
    指挥者类负责按照特定的顺序调用建造者的方法来构建产品。它将建造者的具体实现与构建过程分开,使得构建过程与产品的具体类型解耦。

  5. 客户端(Client)
    客户端负责使用指挥者和建造者来构建产品。客户端通常不需要知道产品的具体构建过程或其组成部分。

四、总结

建造者模式模仿建筑行业的建造行为,设计师设计好图纸交给工程队,工程队根据图纸建造房子,房子建造好之后交给客户。设计的代码中将构造(设计师的图纸)和表示(工程队造的房子)完美分离,这样可以把复杂的部分简单化,最后有机地组合在一起最终形成我们想要的产品。

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

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

相关文章

【Mysql】mysql三种安装方式(二进制、yum、docker)

一、环境信息 centos7.6_x86、glib2.17 mysql官网下载地址&#xff1a;MySQL :: Download MySQL Community Server 二、 二进制安装 #下载解压安装包 [roothadoop03 ~]# wget -c https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.39-linux-glibc2.17-x86_64.tar.xz [ro…

PX4二次开发快速入门

文章目录 前言一、概述二、二次开发基础&#xff08;自定义工作队列&#xff0c;自定义uorb&#xff09;三、自定义串口驱动&#xff08;添加一个毫米波雷达并定高&#xff09;四、自定义I2C驱动&#xff08;驱动一个oled显示屏&#xff09;五、自定义参数六、自定义日志七、自…

机器学习笔记:编码器与解码器

目录 介绍 组成结构 代码实现 编码器 解码器 合并编码器-解码器 思考 介绍 在机器翻译中&#xff0c;输入的序列与输出的序列经常是长度不相等的序列&#xff0c;此时&#xff0c;像自然语言处理这种直接使用循环神经网络或是门控循环单元的方法就行不通了。因此&#x…

Qt 窗口:菜单、工具与状态栏的应用

目录 引言&#xff1a; 1. 菜单栏 1.1 创建菜单栏 1.2 在菜单栏中添加菜单 1.3 创建菜单项 1.4 在菜单项之间添加分割线 1.5 综合示例 2.工具栏 2.1 创建工具栏 2.2 设置停靠位置 2.3 设置浮动属性 2.4 设置移动属性 3. 状态栏 3.1 状态栏的创建 3.2 在状态栏中显…

Pytorch_cuda版本的在线安装命令

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 运行效果如下&#xff1a; 这个方法是直接从pytorch官网进行在线下载和安装。 cu121&#xff0c;表示当前您安装的cuda版本是12.1

java基础概念15-字符串

public static void main(String[] args) {String name "张三";name "李四";System.out.println(name);// 李四} name变量是一个引用变量&#xff0c;它存储的是对字符串对象的引用&#xff08;即内存地址&#xff09;&#xff0c;而不是字符串对象本身的…

【Git】远程仓库新建分支后,拉到本地开发

1. 在远程仓库上创建分支 2. git fetch origin&#xff1a;在本地同步远程仓库的分支&#xff08;获取远程仓库所有分支的所有修改&#xff09; 3. git remote -a&#xff1a;查看所有分支&#xff08;远程&#xff0b;本地&#xff09; 4. git checkout -b 本地名 远程仓库…

华夏erp2.3代码审计

1 sql注入代码 该项目使用的是Mybits的数据库,直接在*.xml文件中全局搜索 ${我们选一个比较有可能有注入的 UserMapperEx.xml 进行查 看 回溯到UserMapperEx.java。 继续回溯到UserService.java。 继续回溯可以看到UserComponent.java中userName的值是从search中获取的。 在s…

CodeWave--创建实体与枚举

一、实体的创建 可视化开发左侧边栏选择数据模块&#xff0c;在实体菜单下&#xff0c;选择2处的“” &#xff0c;即可创建一个默认的实体类&#xff0c;修改3处的实体名称&#xff0c;再在实体页签中&#xff0c;添加所需的字段即可。 注&#xff1a;id是自动生成的主键&…

域名是什么?1分钟快速了解

任何一个互联网上的设备&#xff0c;包括服务器或我们的个人电脑设备&#xff0c;都有一个对应的地址&#xff0c;即IP地址&#xff0c;&#xff08;比如&#xff0c;192.168.1.1)。所有设备&#xff0c;都通过这个独立唯一的IP地址来互相访问。 由于IP地址不容易被记忆&#…

仅需三步,轻松制作电脑系统安装盘!

系统安装在现在可谓是必不可少的技能。自己系统坏了,不用到电脑安装,省了不少大洋,在朋友面前也可以装装大神,百利无一害呀,还不赶快学起来! 按照以前常规方式,每个电脑系统都会配有一个光盘,然后放到光驱里面读取安装,但随着笔记本越做越薄,光驱慢慢被取消了。所以…

广州网站建设运营团队

广州是中国南部的一座国际化大都市&#xff0c;拥有众多创新科技企业和互联网公司。随着数字经济的快速发展&#xff0c;网站建设和运营已经成为企业发展和推广的重要手段。作为一支专业的网站建设运营团队&#xff0c;我们深知在这个信息化时代&#xff0c;拥有一个优质的网站…

React 学习——react项目中加入echarts图

实现的代码如下&#xff1a; import * as echarts from echarts import { useEffect, useRef } from react; const Home ()>{const chartRef useRef(null);useEffect(()>{// const chartDom document.getElementById(main);//使用id获取节点const chartDom chartRef…

Linux系统驱动(十六)platform驱动

文章目录 一、简介&#xff08;一&#xff09;device、bus、driver模型&#xff08;二&#xff09;platform驱动原理 二、platform总线驱动的API&#xff08;一&#xff09;设备信息端&#xff08;二&#xff09;设备驱动端&#xff08;三&#xff09;驱动中获取设备信息函数&a…

【子豪兄】精讲CS231N斯坦福计算机视觉公开课学习笔记

wx 搜索 gzh 司南锤&#xff0c;回复 子豪兄231笔记 可获取笔记文件&#xff08;pdfdoc) 文章目录 学习链接:- 斯坦福大学公开课- 计算机视觉发展历史- 图像分类算法- 线性分类、损失函数与梯度下降- 神经网络与反向传播- 卷积神经网络- 可视化卷积神经网络- 训练神经网络 &…

关于WMS仓储管理系统的开发与应用

在当今这个全球化与数字化交织并进的时代&#xff0c;高效的仓储管理已经跃升为企业运营效能与市场竞争力提升的关键驱动力。仓库&#xff0c;这一供应链体系中的核心枢纽&#xff0c;其角色已远远超越了简单的货物存储功能&#xff0c;而是成为了推动货物流转效率与精准度的战…

软件测试之面试常见问题大全

软件测试之常见软件测试面试题 面试题解读&#xff0c;轻轻松松过面试&#xff0c;我以一个过来人的身份&#xff0c;写下这篇面试常见问题 1. 最常见的就是&#xff0c;为什么想进本公司&#xff0c;你了解本公司的业务吗&#xff1f; 再回答这个问题的时候是灵活的&#x…

DHCP学习笔记

1.DHCP快速配置 1.1配置接口IP R1: sysname R1 undo info-center enable interface Ethernet0/0/0 ip address 192.168.1.1 255.255.255.0 quit 1.2开启DHCP服务&#xff0c;接着在R1的e0/0/0配置DHCP Server功能 dhcp enable #全局下开启DHCP服务 interface Ethernet…

深度强化学习,模型改进

深度强化学习&#xff1a;DQN、PPO、DDPG、A3C、TD3、SAC、Rainbow、MADDPG、模仿学习&#xff0c;提供创新点&#xff0c;实验对比&#xff0c;代文章、润色 代码不收敛 菲涅尔模型 python深度学习算法模型定制

事务消息使用及方案选型思考

1. 事务消息概念与重要性 1.1 分布式系统中的事务问题 在分布式系统中&#xff0c;事务的一致性是一个核心问题。以电商登录送积分活动为例&#xff0c;用户登录成功后&#xff0c;系统需要执行两个关键操作&#xff1a;记录登录日志和发放积分。这两个操作需要保持一致性&am…