当前位置: 首页 > article >正文

设计模式(创建型)-建造者模式

定义

        建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。该模式允许通过多个简单的步骤逐步构建出一个复杂的对象,用户只需指定复杂对象的类型和内容,而无需了解内部具体的构建细节。

类图

角色

        建造者模式包含四个主要角色,其类图结构如下:​

  1. 产品角色(Product):包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。例如,一个房屋对象,它可能包含墙体、屋顶、门窗等部件。​

  2. 抽象建造者(Builder):定义了创建产品各个子部件的抽象方法接口,通常还包含一个返回复杂产品的方法 getResult()。例如,定义一个建造房屋的抽象接口,其中包含创建墙体、屋顶、门窗等抽象方法。​

  3. 具体建造者(Concrete Builder):实现抽象建造者接口,完成复杂产品各个部件的具体创建方法。例如,实现建造普通房屋的具体建造者类,实现抽象接口中创建墙体、屋顶、门窗等具体逻辑。​

  4. 指挥者(Director):调用建造者对象中的部件构造与装配方法完成复杂对象的创建,指挥者中不涉及具体产品的信息。例如,一个房屋建造指挥者,它调用建造者对象的方法,按照一定顺序构建房屋。

优缺点

优点​

  • 封装性好,构建和表示分离:将复杂对象的构建过程封装在建造者类中,客户端只需要关心如何使用建造者创建对象,而无需了解对象内部的构建细节,使得代码的耦合度降低,维护性提高。​

  • 拓展性好:各个具体的建造者相互独立,增加新的具体建造者无需修改原有类库的代码,符合 “开闭原则”。例如,如果需要增加一种新类型的房屋建造,只需要新增一个具体建造者类实现抽象建造者接口即可,不会影响到其他部分的代码。​

  • 便于控制细节风险:客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其他模块产生任何影响。例如,在建造房屋时,建造者可以根据实际情况对墙体的厚度、屋顶的材质等细节进行调整,而不会影响到房屋的整体结构和其他部分的构建。​

缺点​

  • 产品的组成部分必须相同,限制适用范围:该模式要求产品的组成部分相对固定,如果产品的结构和组成经常变化,使用建造者模式可能不太合适。例如,如果房屋的基本组成部分(如墙体、屋顶、门窗)经常变动,那么使用建造者模式就需要频繁修改各个建造者类和相关的代码,维护成本较高。​

  • 后期维护成本较大:如果产品的内部变化复杂,产品内部发生变化时,建造者也要同步修改。例如,当房屋的结构发生重大变化,如从传统的砖混结构变为框架结构时,所有的具体建造者类都需要相应地修改创建部件的方法,这可能会涉及到大量的代码修改和测试工作。

建造者模式和工厂模式比较

        建造者模式和工厂模式都属于创建型设计模式,但它们的关注点不同:​

  • 建造者模式注重零部件的组装过程:强调通过一步步的构建过程来创建复杂对象,将对象的构建和表示分离,更侧重于描述如何将多个简单部件组合成一个复杂对象。例如,建造房屋时,关注墙体、屋顶、门窗等部件如何按照一定顺序组装成一个完整的房屋。​

  • 工厂模式更注重零部件的创建过程:主要用于创建对象,它提供了一种创建对象的方式,将对象的创建和使用分离,重点在于根据不同的条件创建不同类型的对象。例如,工厂模式可以根据客户需求创建不同类型的汽车,而不关注汽车内部零部件的组装过程。​

        在实际应用中,两者可以结合使用。例如,在生产汽车时,工厂模式负责创建汽车的各个零部件(如发动机、轮胎等),而建造者模式负责将这些零部件组装成一辆完整的汽车。

使用场景

创建复杂对象结构​

        当需要创建的对象是由多个部件构成,且这些部件的组合方式多样时,建造者模式能派上大用场。以电商平台为例,订单对象的创建过程颇为复杂,订单包含用户信息、收货地址、商品列表、促销优惠、支付方式等多个部件。利用建造者模式,可将订单的构建过程进行拆分,让具体建造者分别负责构建各个部件,指挥者按照既定的业务逻辑,将这些部件组合成完整的订单对象。这样一来,不仅创建订单的逻辑更加清晰,后续若要新增或修改订单的某个部件,只需调整相应的建造者类,不会对整体的订单创建流程造成过大影响。​

用户交互与配置生成​

        在交互式应用程序中,用户通常会通过界面设置各种参数来生成特定的对象。以游戏开发为例,玩家在创建游戏角色时,需要对角色的种族、职业、外貌、技能等多项属性进行配置。运用建造者模式,可为每种角色类型创建对应的具体建造者,玩家通过界面输入配置信息,指挥者依据这些信息调用相应的建造者方法,构建出符合玩家需求的游戏角色。这种方式将角色创建的复杂逻辑封装在建造者和指挥者中,使得用户界面与角色创建逻辑解耦,提升了代码的可维护性和扩展性。​

分步骤创建和延迟创建​

        在某些场景下,对象的创建并非一蹴而就,可能需要分多个步骤完成,或者根据特定条件延迟创建对象的某些部分。以报表生成系统为例,报表对象可能包含数据表格、图表、文字说明等多个部分。借助建造者模式,可以先创建报表的基本结构,然后根据用户的请求逐步生成数据表格、图表等内容。当数据量较大时,还能通过延迟创建的方式,避免在系统启动时就进行大量的数据加载和报表生成操作,提升系统的响应速度和性能。​

多平台适配​

        当需要为不同的平台或环境创建对象时,建造者模式同样适用。以移动应用开发为例,应用可能需要针对 iOS 和 Android 平台生成不同风格的界面布局。通过创建不同平台对应的具体建造者,分别负责生成适用于各自平台的界面元素,指挥者则根据运行平台调用相应的建造者,创建出符合平台特性的界面。这种方式将平台相关的代码封装在具体建造者中,便于对不同平台的界面进行独立维护和更新。​

构建链式操作对象​

        在一些流式 API 的设计中,常常会使用建造者模式来实现链式操作。以 Java 的Stream API 为例,通过链式调用各种方法,可以对数据进行筛选、映射、排序等一系列操作。建造者模式通过链式调用的方式,将多个操作步骤串联起来,使代码更加简洁和可读。用户只需关注每个操作的逻辑,而无需关心对象的创建和组装过程,极大地提升了代码的开发效率。

使用案例

Java  StringBuilder

        在 Java 中,StringBuilder 类的使用类似于建造者模式。StringBuilder 用于创建可变的字符串对象,它提供了一系列方法来逐步构建字符串。

1. 类比建造者模式的角色:

  • StringBuilder 类可以看作是具体建造者,它实现了构建字符串的具体方法。例如,append() 方法用于将各种类型的数据追加到字符串中,类似于具体建造者创建产品部件的方法。​

  • StringBuilder 类中的 toString() 方法可以类比为抽象建造者中的 getResult() 方法,用于返回最终构建好的字符串对象(产品)。

2. 使用示例:

StringBuilder sb = new StringBuilder();

sb.append("Hello");

sb.append(", ");

sb.append("World!");

String result = sb.toString();

System.out.println(result);

        通过 StringBuilder 的 append() 方法逐步构建字符串,最后通过 toString() 方法得到完整的字符串,体现了建造者模式逐步构建复杂对象的思想。虽然 StringBuilder 并不是严格意义上的建造者模式实现,但它的设计思路和使用方式与建造者模式有相似之处,帮助我们更好地理解和运用建造者模式的概念。 

相关文章:

设计模式(创建型)-建造者模式

定义 建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。该模式允许通过多个简单的步骤逐步构建出一个复杂的对象,用户只需指定复杂对象…...

RIP和OSPF的区别

文章目录 RIP(路由信息协议)和 OSPF(开放最短路径优先)是两种常见的动态路由协议,它们的主要区别如下:1. 协议类型2. 更新方式3. 路由计算算法4. 最大跳数5. 管理距离(AD)6. 认证机制…...

Git 之配置ssh

1、打开 Git Bash 终端 2、设置用户名 git config --global user.name tom3、生成公钥 ssh-keygen -t rsa4、查看公钥 cat ~/.ssh/id_rsa.pub5、将查看到的公钥添加到不同Git平台 6、验证ssh远程连接git仓库 ssh -T gitgitee.com ssh -T gitcodeup.aliyun.com...

遍历数组时,如何获取数组每个元素索引号

在 JavaScript 中&#xff0c;有多种方法可以在遍历数组时获取每个元素的索引号&#xff0c;下面为你介绍几种常用的方法&#xff1a; 1. 使用 for 循环 const array [apple, banana, cherry]; for (let i 0; i < array.length; i) {console.log(索引 ${i} 的元素是: ${…...

黑马点评项目

遇到问题&#xff1a; 登录流程 session->JWT->SpringSession->tokenRedis &#xff08;不需要改进为SpringSession&#xff0c;token更广泛&#xff0c;移动端或者前后端分离都可以用&#xff09; SpringSession配置为redis模式后&#xff0c;redis相当于分布式se…...

如何防御TCP洪泛攻击

TCP洪泛攻击&#xff08;TCP Flood Attack&#xff09;是一种常见的分布式拒绝服务&#xff08;DDoS&#xff09;攻击手段&#xff0c;以下是其原理、攻击方式和危害的详细介绍&#xff1a; 定义与原理 TCP洪泛攻击利用了TCP协议的三次握手过程。在正常的TCP连接建立过程中&a…...

【AVRCP】AVRCP核心术语解析

目录 一、协议核心术语&#xff1a;架构的基石 1.1 音视频控制协议簇&#xff08;AVRCP 生态链&#xff09; 1.2 数据传输协议&#xff08;L2CAP 核心术语&#xff09; 二、设备架构术语&#xff1a;角色与交互 2.1 设备角色模型&#xff08;CT/TG 二元架构&#xff09; …...

【弹性计算】异构计算云服务和 AI 加速器(四):FPGA 虚拟化技术

异构计算云服务和 AI 加速器&#xff08;四&#xff09;&#xff1a;FPGA 虚拟化技术 &#x1f680; FPGA&#xff08;Field-Programmable Gate Array&#xff0c;现场可编程门阵列&#xff09;是一种可重构的半导体芯片&#xff0c;允许用户根据需要动态配置硬件逻辑&#xff…...

Python爬虫如何检测请求频率?

在进行网络爬虫开发时&#xff0c;合理设置请求频率是确保爬虫稳定运行、避免被目标网站封禁的关键策略之一。以下是一些有效的方法和最佳实践&#xff0c;帮助你合理设置请求频率&#xff0c;确保爬虫的可持续性和稳定性。 一、了解速度限制的原因 网站对爬虫速度进行限制的…...

编译原理——自底向上语法优先分析

文章目录 自底向上优先分析概述一、自底向上优先分析概述二、简单优先分析法&#xff08;一&#xff09;优先关系定义&#xff08;二&#xff09;简单优先文法的定义&#xff08;三&#xff09;简单优先分析法的操作步骤 三、算法优先分析法&#xff08;一&#xff09;直观算符…...

nuxt3网站文章分享微信 ,QQ功能

1.安装 npm install qrcode --save-dev 2.组件使用 <div class"share"><div style"line-height: 69px; color: #fff;width: 100px;"><p style"text-align: center;">分享:</p></div><div click"shareToMi…...

智能任务分配:Python高并发架构设计

Python并发编程实战&#xff1a;多进程与多线程的智能任务分配策略 引言&#xff1a;突破性能瓶颈的关键选择 在CPU核心数量激增和I/O密集型应用普及的今天&#xff0c;Python开发者面临着一个关键抉择&#xff1a;如何通过并发编程充分释放硬件潜力&#xff1f;本文通过实测数…...

Oracle 数据库通过exp/imp工具迁移指定数据表

项目需求&#xff1a;从prod数据库迁移和复制2个表(BANK_STATE&#xff0c;HBS)的数据到uat数据库环境。 数据库版本&#xff1a;Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 迁移工具&#xff1a;客户端exp/imp工具 -- 执行命令 从Prod数据库导出数据exp us…...

批发订货系统:驱动企业数字化转型的核心引擎

在数字经济时代&#xff0c;传统批发企业正面临供应链效率低、客户体验不足、管理成本高等挑战。而批发订货系统作为企业数字化转型的重要工具&#xff0c;正通过智能化、数据化和流程重构&#xff0c;重塑企业的运营模式&#xff0c;助力企业实现降本增效与业务创新。以下从多…...

STM32F103_LL库+寄存器学习笔记07 - 串口接收缓冲区非空中断

导言 上一章节《STM32F103_LL库寄存器学习笔记06 - 梳理串口与串行发送“Hello,World"》梳理完USART的基本设置与发送字符串“Hello,World"&#xff0c;接着梳理接收缓冲区非空中断。 实用的串口接收程序都会使用中断方式&#xff0c;不会使用轮询方式。最主要的原因…...

python将整个txt文件写入excel的一个单元格?

要将整个txt文件写入Excel的一个单元格&#xff0c;可以使用Python的openpyxl库来实现。以下是一个简单的示例代码&#xff1a; from openpyxl import Workbook# 读取txt文件内容 with open(file.txt, r) as file:txt_content file.read()# 创建一个新的Excel工作簿 wb Work…...

CentOS 8 Stream 配置在线yum源参考 —— 筑梦之路

CentOS 8 Stream ISO 文件下载地址&#xff1a;http://mirrors.aliyun.com/centos-vault/8-stream/isos/x86_64/CentOS-Stream-8-20240603.0-x86_64-dvd1.isoCentOS 8 Stream 网络引导ISO 文件下载地址&#xff1a;http://mirrors.aliyun.com/centos-vault/8-stream/isos/x86_6…...

生物中心论

Robert Lanza的“生物中心论”&#xff08;Biocentrism&#xff09;是一种以生命和意识为核心的宇宙观&#xff0c;试图颠覆传统科学对时间、空间和物质的理解。 一、核心观点 意识创造宇宙 生物中心论认为&#xff0c;宇宙的存在依赖于观察者的意识。传统科学将宇宙视为独立实…...

LeetCode //C - 650. 2 Keys Keyboard

650. 2 Keys Keyboard There is only one character ‘A’ on the screen of a notepad. You can perform one of two operations on this notepad for each step: Copy All: You can copy all the characters present on the screen (a partial copy is not allowed).Paste:…...

【leetcode hot 100 347】前 K 个高频元素

解法一&#xff1a;用map的value记录key出现的次数&#xff0c;用PriorityQueue构造最小堆。 class Solution {public int[] topKFrequent(int[] nums, int k) {// 把元素放在map中Map<Integer,Integer> map new HashMap<>();for(int num:nums){if(map.containsK…...

Spring三级缓存解决循环依赖的深度解析

一、循环依赖场景 假设存在两个Bean的相互依赖&#xff1a; Component public class ServiceA {Autowiredprivate ServiceB serviceB; }Component public class ServiceB {Autowiredprivate ServiceA serviceA; }二、三级缓存定义 在 DefaultSingletonBeanRegistry 中定义&a…...

Spring AOP:面向切面编程的探索之旅

目录 1. AOP 2. Spring AOP 快速入门 2.1 引入 Spring AOP 依赖 2.2 Spring AOP 简单使用 3. Spring AOP 核心概念 3.1 切点 3.1.1 Pointcut 定义切点 3.1.2 切点表达式 3.1.2.1 execution 表达式 3.1.2.2 annotation 表达式 3.2 连接点 3.3 通知(Advice) 3.3.1 通…...

使用QT画带有透明效果的图

分辨率&#xff1a;24X24 最大圆 代码: #include <QApplication> #include <QImage> #include <QPainter>int main(int argc, char *argv[]) {QImage image(QSize(24,24),QImage::Format_ARGB32);image.fill(QColor(0,0,0,0));QPainter paint(&image);…...

RocketMQ可视化工具使用 - Dashboard(保姆级教程)

1、github拉取代码&#xff0c;地址&#xff1a; https://github.com/apache/rocketmq-dashboard 2、指定Program arguments&#xff0c;本地启动工程 勾上这个Program arguments&#xff0c;会出现多一个对应的框 写入参数 --server.port1280 --rocketmq.config.namesrvAddr…...

用Unity实现UDP客户端同步通信

制作UDPNetMgr网络管理模块 这段代码定义了一个名为UDPNetMgr的 Unity 脚本类&#xff0c;用于管理 UDP 网络通信&#xff0c;它作为单例存在&#xff0c;在Awake方法中创建收发消息的线程&#xff0c;Update方法处理接收到的消息&#xff1b;StartClient方法启动客户端连接&a…...

pandoc安装及基础使用

pandoc安装 访问pandoc tags,切换至想要安装的版本&#xff0c;本次安装3.6.4 下载windows版本 下载texlive镜像&#xff0c;将文件转换成pdf需要用到 点开后会进入最近的镜像网站 下载完成后解压iso文件&#xff0c;以管理员身份运行install-tl-windows.bat&#xff…...

C++:无序关联容器

遇到的问题&#xff0c;都有解决方案&#xff0c;希望我的博客能为您提供一点帮助。 一、无序关联容器概述 无序关联容器&#xff08;如 unordered_set、unordered_map、unordered_multiset、unordered_multimap&#xff09;基于 ​哈希表&#xff08;Hash Table&#xff09;​…...

3.27学习总结 算法题

自己用c语言做的&#xff0c;不尽如意 后面看了题解&#xff0c;用的是c&#xff0c;其中string 变量和字符串拼接感觉比c方便好多&#xff0c;可以用更少的代码实现更好的效果&#xff0c;打算之后去学习c&#xff0c;用c写算法。 递归&#xff0c;不断输入字符&#xff0c;…...

案例分享|树莓派媒体播放器,重构商场广告的“黄金三秒”

研究显示&#xff0c;与传统户外广告相比&#xff0c;数字户外广告在消费者心中的记忆率提高了17%&#xff0c;而动态户外广告更是能提升16%的销售业绩&#xff0c;整体广告效率提升了17%。这一显著优势&#xff0c;使得越来越多资源和技术流入数字广告行业。 户外裸眼3D广告 无…...

Redisson - 分布式锁和同步器

文章目录 锁&#xff08;Lock&#xff09;公平锁&#xff08;Fair Lock&#xff09;联锁&#xff08;MultiLock&#xff09;红锁&#xff08;RedLock&#xff09; 【已废弃】读写锁&#xff08;ReadWriteLock&#xff09;信号量&#xff08;Semaphore&#xff09;可过期许可信号…...