设计模式-04 设计模式-Builder

设计模式-04 设计模式-Builder

1.定义

建造者模式(Builder Pattern)是一种创建型设计模式,它允许你使用不同的构建步骤来创建复杂的对象。
建造者模式的定义是:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

                                       指挥者|/         \\/           \\/             \\具体建造者 A       具体建造者 B|               |/               |_______________/_______________|______________|                                              ||                                              ||                                              |_______|______________________________________________|____|                                                          ||                      已构建的产品                         ||__________________________________________________________|

在这个 ASCII 图中:

  • 指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。
  • 具体建造者代表不同的产品类型或变体。每个具体建造者负责构建产品的一个或多个部分。
  • 已构建的产品是建造过程的结果。

建造过程如下:

  1. 指挥者创建一个具体建造者。
  2. 指挥者调用具体建造者的构建方法来创建产品的不同部分。
  3. 指挥者可以调用多个具体建造者来创建复杂的产品结构。
  4. 一旦所有部分都构建完成,指挥者调用具体建造者的获取产品方法来检索已构建的产品。
2.内涵


换句话说,建造者模式将对象的构建过程与对象的表示分离。这使得你可以使用相同的构建过程来创建不同类型的对象,而无需更改构建代码本身。

建造者模式包含以下角色:

  • 建造者(Builder):负责创建和组装最终的对象。
  • 具体建造者(Concrete Builder):实现建造者接口,并负责创建和组装最终对象的特定部分。
  • 指挥者(Director):负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。
  • 产品(Product):最终创建的对象。
3.案例对比

不用 Builder 设计模式

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <fstream>
#include <tuple>
#include <sstream>
#include <memory>
using namespace std;/***  <p>hello</p><ul> <li>hello</li> <li>world</li></ul>* @return*/
int main() {auto text= "hello";string output;output+="<p>";output+=text;output+="</p>";cout<<output<<endl;string words[] = {"hello", "world"};ostringstream oss;oss<<"<ul>";for(auto w: words){oss<<" <li>" << w <<"</li>";}oss<<"</ul>";cout<<oss.str()<<endl;return 0;
}


使用 Builder 设计模式

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <fstream>
#include <tuple>
#include <sstream>
#include <memory>
using namespace std;struct HtmlElement
{string name, text;vector<HtmlElement> elements;const size_t indent_size =2;HtmlElement(){}HtmlElement(const string& name,const string& text):name(name),text(text){}string str(int intent = 0)const{ostringstream oss;string i(indent_size*intent, ' ');oss << i << "<" << name << ">" << endl;if(text.size() > 0){oss<<string(indent_size*(intent + 1), ' ') << text <<endl;}for(const auto& e:elements) {oss << e.str(intent + 1);}oss<<i << "</" << name << ">" << endl;return oss.str();}};struct HtmlBuilder
{HtmlElement root;HtmlBuilder(string rootname){root.name = rootname;}void add_child(string child_name, string child_text){HtmlElement e{child_name, child_text};root.elements.emplace_back(e);}string str() const {return root.str();}
};int main() {HtmlBuilder builder ("ul");builder.add_child("li", "hello");builder.add_child("li", "world");builder.add_child("li", "hello");cout << builder.str() << endl;return 0;
}

4.注意事项

在实际使用建造者模式时,需要注意以下几点和原则:

1. 分离接口和实现

建造者模式的核心原则是将对象的构建过程与它的表示分离。因此,建造者接口应该只定义创建和组装对象所需的方法,而具体的实现细节应该委托给具体建造者。

2. 确保建造者产品的一致性

指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。为了确保建造出的产品是一致的,指挥者需要使用相同的建造者接口来调用所有具体建造者。

3. 灵活性和可扩展性

建造者模式的优点之一是它的灵活性和可扩展性。你可以轻松地添加新的具体建造者来创建新的对象类型,而无需修改现有代码。这使得建造者模式非常适合需要创建各种不同对象的场景。

4. 避免创建不必要的具体建造者

虽然建造者模式允许你创建任意数量的具体建造者,但重要的是要避免创建不必要的具体建造者。每个具体建造者都应该代表一种不同的对象类型或变体。

5. 考虑使用不可变对象

对于需要不可变对象的场景,你可以考虑使用不可变对象来表示产品。这可以防止在构建过程之后意外修改对象。

6. 性能考虑

如果性能是一个问题,你需要仔细考虑建造者模式的开销。创建和销毁大量的具体建造者可能会对性能产生影响。

7. 何时使用建造者模式

建造者模式最适合用于创建复杂的对象,这些对象需要经过多个构建步骤才能创建。例如,它可以用在创建文档、GUI 控件或 Web 页面等对象中。


个人觉得如果对象很简单,并且不需要经过多个构建步骤,则建造者模式可能过于复杂。在这种情况下,可以使用更简单的创建模式,例如工厂方法模式或单例模式会更简单。


5.最佳实践


建造者模式的最佳实践包括:

  • 使用不可变对象:对于需要不可变对象的场景,使用不可变对象来表示产品可以防止在构建过程之后意外修改对象。
  • 使用分层建造者:对于复杂的对象,可以考虑使用分层建造者。分层建造者将构建过程分解成更小的步骤,并允许你创建嵌套的对象结构。
  • 使用流式 API:对于需要创建大量相似对象的场景,可以使用流式 API 来简化构建过程。流式 API 允许你将构建步骤链接在一起,并使用链式语法来创建对象。
  • 考虑使用生成器函数:在某些情况下,使用生成器函数可以简化建造者模式的实现。生成器函数可以让你一步一步地构建对象,而无需显式地创建和销毁具体建造者。
  • 避免创建不必要的具体建造者:每个具体建造者都应该代表一种不同的对象类型或变体。避免创建不必要的具体建造者,因为这会增加代码的复杂性和维护成本。
  • 确保建造者产品的一致性:指挥者负责协调建造过程,它告诉建造者要创建哪些部分以及如何组装它们。为了确保建造出的产品是一致的,指挥者需要使用相同的建造者接口来调用所有具体建造者。
6.总结

如果性能是一个问题,你需要仔细考虑建造者模式的开销。创建和销毁大量的具体建造者可能会对性能产生影响。

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

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

相关文章

信号,信号列表,信号产生方式,信号处理方式

什么是信号 信号在我们的生活中非常常见&#xff1b;如红绿灯&#xff0c;下课铃&#xff0c;游戏团战信号&#xff0c;这些都是信号&#xff1b;信号用来提示接收信号者行动&#xff0c;但接收信号的人接收到信号会进行一系列的行为&#xff0c;完成某个动作&#xff1b;这就…

CAN测试工具

CAN测试工具是用于测试CAN&#xff08;Controller Area Network&#xff09;总线通信的软件工具。这些工具主要用于汽车电子控制系统、工业现场、电梯控制系统、电力通讯、安防监控系统、船舶运输、轨道交通、医疗设备、纺织机械、楼宇控制等监控系统的开发和测试。 常见的CAN…

cmake的使用方法: 多个源文件的编译

一. 简介 前面一篇文章学习了针对只有一个 .c源文件&#xff0c;如何编写 CMakeLists.txt内容&#xff0c;从而使用 cmake工具如何编译工程。文章如下&#xff1a; cmake的使用方法: 单个源文件的编译-CSDN博客 本文学习针对 多个 .c源文件&#xff0c; CMakeLists.txt文件如…

融创共赢,算网领航 | 移动云智能芯片开放实验室正式发布

4月29日上午&#xff0c;中国移动算力网络大会“融创共赢&#xff0c;算网领航-算网原生技术”分论坛在苏州金鸡湖国际会议中心顺利召开&#xff0c;中国移动云能力中心副总经理吴世俊出席论坛并发表致辞。大会举行了智能芯片开放实验室发布仪式&#xff0c;同时发布移动云最新…

CogAgent:开创性的VLM在GUI理解和自动化任务中的突破

尽管LLMs如ChatGPT在撰写电子邮件等任务上能够提供帮助&#xff0c;它们在理解和与GUIs交互方面存在挑战&#xff0c;这限制了它们在提高自动化水平方面的潜力。数字世界中的自主代理是许多现代人梦寐以求的理想助手。这些代理能够根据用户输入的任务描述自动完成如在线预订票务…

【模板】前缀和

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 前缀和模板题。 前缀和中数组下标为1~n。 前缀和&#xff1a;pre[i]pre[i-1]a[i]; 某段区间 [l,r]的和&#xff1a;pre[r]-pre[l-1] 3.…

android天气实战

页面绘制 问题1、下拉框需要背景为透明 我懒得写全部省份就写了5个所以不需要往下 图标准备 iconfont-阿里巴巴矢量图标库几坤年没来这了好怀念啊&#xff0c;图标库选择下雨的图标等 准备网络请求 0、API接口准备 api免费七日天气接口API 未来一周天气预报api (tianqiap…

前端业务开发中使用原生js和elementui两种方式实现头像裁切上传的功能

日常业务开发中&#xff0c;无论是后台管理系统还是前台界面&#xff0c;都会遇到图片裁剪的业务需求&#xff0c;选择合适的尺寸或者图片的关键部分&#xff0c;满足我们的功能需求&#xff01;&#xff01; 效果预览 效果一&#xff1a; 效果二: 实现过程 1.原生js实现方…

VS(Visual Studio)中查找项目里的中文字符

目录 正则表达式查找中文字符 正则表达式查找中文字符 在Visual Studio (VS) 中查找所有的中文字符&#xff0c;你可以使用其强大的查找和替换功能。不过&#xff0c;由于中文字符的范围非常广泛&#xff08;包括简体中文、繁体中文、日本汉字、韩国汉字等&#xff09;&#xf…

GPT3 终极指南(一)

原文&#xff1a;zh.annas-archive.org/md5/6de8906c86a2711a5a84c839bec7e073 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 前言 GPT-3&#xff0c;或者说是 Generative Pre-trained Transformer 3&#xff0c;是由 OpenAI 开发的基于 Transformer 的大型语言模型…

React 组件性能优化

React 组件性能优化的核心是减少渲染真实 DOM 节点的频率&#xff0c;减少 Virtual DOM 比对的频率。 1. 组件卸载前进行清理操作 window 注册的全局事件, 以及定时器 useEffect(()>{return ()>{// do somethingclearTimeout(tiemr)window.removeEventListener(xxx, c…

JavaScript 中 for、for...of 和 for...in 循环

在 JavaScript 中&#xff0c;有多种循环语句可用于迭代和遍历数据。其中最常用的三种是 for、for...of 和 for...in 循环。下面对它们进行详细解释&#xff1a; for 循环&#xff1a;for 循环是一种常见的循环结构&#xff0c;用于按照指定的条件重复执行代码块。语法如下&…

平安城市 校园 景区 停车场网络语音对讲立柱SV-11TS

平安城市 校园 景区 停车场网络语音对讲立柱SV-11TS 长方形立柱式设计&#xff0c;外观简约&#xff0c;线条优美&#xff0c;工艺考究&#xff0c;坚固耐用可一键实现在紧急情况下求助报警、事件咨询&#xff0c;与SIP网络对讲主机进行全双工对讲。内置警示灯&#xff0c;呼叫…

iOS ------ Method Swizzling (动态方法交换)

一&#xff0c;Method Swizzling 简介 Method&#xff08;方法&#xff09;对应的是objc_method结构体&#xff1b;而objc_method结构体中包含了SEL method_name(方法名&#xff09;&#xff0c;IMP method_imp&#xff08;方法实现&#xff09; // objc_method 结构体 typed…

Linux下启动jenkins报错问题解决

jenkins端口报错 java.io.IOException: Failed to start Jettyat winstone.Launcher.<init>(Launcher.java:209)at winstone.Launcher.main(Launcher.java:496)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.int…

【题目】2023年全国职业院校技能大赛 GZ073 网络系统管理赛项赛题第3套A模块

2023年全国职业院校技能大赛 GZ073网络系统管理赛项 赛题第3套 信息安全管理与评估 网络系统管理 网络搭建与应用 云计算 软件测试 移动应用开发等多个赛项技术支持 任务书&#xff0c;赛题&#xff0c;解析等资料&#xff0c;知识点培训服务 添加博主wx&#xff1a;liuliu54…

全国产化BMC子卡详细介绍

一款基于全国产的BMC子卡&#xff0c;可实现ChMC/IPMC功能。子卡遵循IPMI 1.5/2.0协议规范&#xff0c;也支持客制OEM命令。子卡可获取载板板卡环境信息&#xff0c;板卡属性信息和板卡状态信息等&#xff0c;其中包括温度、电压、电流等信息&#xff1b;FRU、系统版本、CPU型号…

Django整合多种认证方式

承接上一篇&#xff1a;Django知识点总结-CSDN博客 目录 25.使用 Django REST framework实现用户认证和授权 26.通过djangorestframework-simplejwt使用JWT(JSON Web Token) 27.使用django-auth-ldap进行用户认证 28. 使用django-cas-ng实现集中认证及实现单点登录 29. …

实时监控视频拼接系统:功能和拼接参数介绍

目录 一、实时视频拼接系统介绍 &#xff08;一&#xff09;实时视频拼接的定义 &#xff08;二&#xff09;主要功能 1、视频拼接 2、拼接形式选择 3、前端选择 4、拼接展示 5、数据处理效率提升 6、任务管理 &#xff08;三&#xff09;实时拼接效果 二、拼接需要…

AnolisOS8.8基于yum安装mariadb并进行授权管理

1 安装并启动MariaDB # 安装 dnf -y install mariadb-server # 设置开机启动并立即启动 systemctl enable --now mariadb2 配置root用户允许远程访问 注意&#xff1a;本机ip地址 一定要替换成自己mariadb服务的ip mysql<<eof grant all privileges on *.* to root本机…