【深入理解设计模式】建造者设计模式

在这里插入图片描述

建造者设计模式

建造者设计模式(Builder Pattern)是一种创建型设计模式,旨在通过将复杂对象的构建过程拆分成多个简单的步骤,使得相同的构建过程可以创建不同的表示。该模式允许您使用相同的构建过程来创建不同的对象表示。

概述

将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

  • 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况。
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象;相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦,实现了更好的复用。
  • 建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

结构

建造者(Builder)模式包含如下角色:

  • 抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。

  • 具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。

  • 产品类(Product):要创建的复杂对象。

  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

实现方式

链式调用:通过返回 Builder 对象本身来实现链式调用,使得可以在一个表达式中连续调用多个方法。
Fluent API:通过使得方法返回类型为 Builder 类型,从而允许在一个表达式中连续调用多个方法。

优点

  • 分步构建:将对象的构建过程拆分成多个步骤,使得构建过程更加灵活,易于管理和维护。
  • 复用性:相同的构建过程可以创建不同的对象表示,提高了代码的复用性。
  • 隐藏复杂性:客户端不需要了解对象的具体构建过程,只需使用建造者和产品即可。

缺点

  • 对象的创建过程被固定:一旦建造者创建的对象的构建过程被固定,就很难改变对象的构建过程。

  • 造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

使用场景

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

  1. 创建复杂对象:当对象的构建过程比较复杂,包含多个步骤或者多个组成部分时,可以考虑使用建造者模式。例如,创建一个包含多个属性的对象,或者对象的构建需要进行复杂的初始化操作。

  2. 创建对象的表示可以灵活变化:如果相同的构建过程可以创建不同的对象表示,可以使用建造者模式来封装对象的构建过程,从而根据需要创建不同的对象表示。

  3. 隐藏构建过程细节:建造者模式可以将对象的构建过程与具体的构建细节分离,从而隐藏了对象的创建细节。客户端只需要关注建造者和产品即可,不需要了解对象的具体构建过程。

  4. 链式调用:建造者模式通常通过返回建造者对象本身来实现链式调用,使得可以在一个表达式中连续调用多个方法,从而提高了代码的可读性和易用性。

  5. 创建过程中需要参数化配置:如果对象的创建过程中需要根据不同的配置参数进行定制化配置,可以使用建造者模式来封装配置参数,并根据不同的配置参数创建不同的对象表示。

总的来说,建造者模式适用于对象构建过程比较复杂,需要进行灵活定制或者隐藏细节的场景,可以帮助简化对象的创建过程,提高代码的可维护性和可扩展性。

示例1:考虑一个创建共享单车对象的建造者模式示例:

/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 复杂产品 - 自行车类*/
public class Bike {private String frame;private String seat;public String getFrame() {return frame;}public void setFrame(String frame) {this.frame = frame;}public String getSeat() {return seat;}public void setSeat(String seat) {this.seat = seat;}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 抽象建造者 - 定义建造复杂对象各个部件的方法*/
public abstract class Builder {protected Bike bike = new Bike();public abstract void buildFrame();public abstract void buildSeat();public abstract Bike creatBike();}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 具体建造者 - 摩拜单车*/
public class MobikeBuilder extends Builder {@Overridepublic void buildFrame() {bike.setFrame("碳纤维车座");}@Overridepublic void buildSeat() {bike.setSeat("真皮车座");}@Overridepublic Bike creatBike() {return bike;}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 具体建造者 - ofo单车*/
public class OfoBuilder extends  Builder{@Overridepublic void buildFrame() {bike.setFrame("铝合金车架");}@Overridepublic void buildSeat() {bike.setSeat("牛皮车座");}@Overridepublic Bike creatBike() {return bike;}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 指挥者*/
public class Direct {private final Builder builder;public Direct(Builder builder) {this.builder = builder;}public Bike construct() {builder.buildFrame();builder.buildSeat();return builder.creatBike();}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 客户端 - 测试类*/
public class Client {public static void main(String[] args) {Direct direct = new Direct(new OfoBuilder());Bike bike = direct.construct();System.out.println(bike.getFrame());System.out.println(bike.getSeat());}
}

通过上述实例,我们将共享单车的构建过程分为多个步骤,在抽象构建者中分别定义了构建各个步骤的方法,在具体构建者中,我们只需要实现这些方法,就可以构建出复杂对象,并且我们可以通过创建不同的具体构建者来通过相同的构建过程构建不同的复杂对象。以上述例子为例,我们创建了两个具体构建者分别是:ofo共享单车构建者 和 摩拜共享单车构建者,在客户端我们只需要将我们希望构建的对象构建者传入指挥者中,即可构建出对应的对象,并且非常容易拓展,符合开闭原则。

示例2:考虑一个创建汽车对象的建造者模式示例:

// Product
class Car {private String make;private String model;private int year;// Constructor, getters and setters...
}// Builder
interface CarBuilder {CarBuilder setMake(String make);CarBuilder setModel(String model);CarBuilder setYear(int year);Car build();
}// Concrete Builder
class CarBuilderImpl implements CarBuilder {private Car car;public CarBuilderImpl() {car = new Car();}@Overridepublic CarBuilder setMake(String make) {car.setMake(make);return this;}@Overridepublic CarBuilder setModel(String model) {car.setModel(model);return this;}@Overridepublic CarBuilder setYear(int year) {car.setYear(year);return this;}@Overridepublic Car build() {return car;}
}// Director
class CarDirector {public Car constructSportsCar(CarBuilder builder) {return builder.setMake("Audi").setModel("A6").setYear(2022).build();}
}// Client
public class Main {public static void main(String[] args) {CarBuilder builder = new CarBuilderImpl();CarDirector director = new CarDirector();Car sportsCar = director.constructSportsCar(builder);System.out.println(sportsCar.getMake());   // Output: AudiSystem.out.println(sportsCar.getModel());  // Output: A6System.out.println(sportsCar.getYear());   // Output: 2022}
}

在上述示例中,通过建造者模式,我们将汽车对象的构建过程拆分成多个步骤,并且可以根据需要创建不同的汽车对象表示。

模式扩展(链式调用)

建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。

/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 手机类*/
public class Phone {private String cpu;private String screen;private String memory;private String mainboard;// 构造器私有化private Phone(Builder builder) {cpu = builder.cpu;screen = builder.screen;memory = builder.memory;mainboard = builder.mainboard;}public static final class Builder {private String cpu;private String screen;private String memory;private String mainboard;public Builder() {}public Builder cpu(String cpu) {this.cpu = cpu;return this;}public Builder screen(String screen) {this.screen = screen;return this;}public Builder memory(String memory) {this.memory = memory;return this;}public Builder mainboard(String mainboard) {this.mainboard = mainboard;return this;}public Phone build() {return new Phone(this);}}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainboard='" + mainboard + '\'' +'}';}public String getCpu() {return cpu;}public void setCpu(String cpu) {this.cpu = cpu;}public String getScreen() {return screen;}public void setScreen(String screen) {this.screen = screen;}public String getMemory() {return memory;}public void setMemory(String memory) {this.memory = memory;}public String getMainboard() {return mainboard;}public void setMainboard(String mainboard) {this.mainboard = mainboard;}
}
/*** @author OldGj 2024/02/21* @version v1.0* @apiNote 测试类*/
public class Client {public static void main(String[] args) {Phone phone = new Phone.Builder().cpu("英特尔").mainboard("华硕").memory("金士顿").screen("三星").build();System.out.println(phone);}
}

链式调用在某种程度上也可以提高开发效率。从软件设计上,对程序员的要求比较高。

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

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

相关文章

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的疲劳驾驶检测系统(Python+PySide6界面+训练代码)

摘要:本研究详述了一种采用深度学习技术的疲劳驾驶检测系统,该系统集成了最新的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等早期算法进行了性能评估对比。该系统能够在各种媒介——包括图像、视频文件、实时视频流及批量文件中——准确地识别疲…

AI工具新革命:从ChatGPT到Sora,生成式AI改变世界

这个春节着实精彩,“春山学”吃透了,不如把目光移向OpenAI又一重磅产品——文生视频大模型Sora。智能新纪元已然开启,因为正如周鸿祎所说:“,Sora的诞生意味着AGI(通用人工智能)的实现将从10年缩短到1年。”…

为什么选择 SaaS SIEM ?

当今的企业越来越依赖技术,这意味着无懈可击的网络安全的重要性怎么强调也不为过。随着组织应对现代数字生态系统的复杂性,维护系统的完整性已不再只是“可有可无”,而是一种必需。  这就是安全信息和事件管理 (SIEM)作为网络安全中最重要…

Stable Diffusion 绘画入门教程(webui)-ControlNet(Seg)

上篇文章介绍了深度Depth,这篇文章介绍下seg(Segmentation) 意思为语义分割, 通俗理解就是把图中的不同物体元素按类别不同,标为不同的颜色,不同的颜色代表不同的元素类别,如下图,左边为原图&a…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的人脸表情识别系统(附完整资源+PySide6界面+训练代码)

摘要:本篇博客呈现了一种基于深度学习的人脸表情识别系统,并详细展示了其实现代码。系统采纳了领先的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等早期版本进行了比较,展示了其在图像、视频、实时视频流及批量文件中识别人脸表情的高…

洛谷 P1038 [NOIP2003 提高组] 神经网络【拓扑序处理】

原题链接:https://www.luogu.com.cn/problem/P1038 题目背景 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别、函数逼近及贷款风险评估等诸多领域有广泛的应用。对神经网络的研究一…

动态绑定样式,uniapp,用三元运算动态绑定多个class类样式,动态绑定的样式可以和原始样式共存

介绍 | uni-app官网 vue、uniapp中动态添加绑定style、class 9种方法实现_vue style动态绑定-CSDN博客 uniapp使用三元运算符动态绑定元素的style样式_uniapp style动态绑定-CSDN博客 对象写法,可以写多个class类 class类的名字:判断条件,最后结果只有…

【TEE论文】硬件辅助安全全面调查:从边缘到云(综述)

原文:A comprehensive survey of hardware-assisted security: From the edge to the cloud 1. 引言 从在中央存储库(例如云主机)中处理收集的传感器数据的传统部署,到更高级的解决方案,例如新兴的边缘计算领域&…

CS50x 2024 - Lecture 8 - HTML, CSS, JavaScript

00:00:00 - Introduction 关于互联网是怎么工作的,如何在他的基础上构建软件 HTML和CSS是描述性语言 javascript一种编程语言,在浏览器上下文中很有用,使得界面更具交互性,也用于服务器 00:01:01 - Bingo Board 00:01:51 - T…

.net core wbeapi 关于swagger的配置

当创建好一个webapi之后,在Program.cs中注释掉原本的AddSwaggerGen,修改为如下配置 Program.cs //builder.Services.AddSwaggerGen();builder.Services.AddSwaggerGen(options >{options.SwaggerDoc("v1", new OpenApiInfo{Version "…

Rainbond实战:3分钟搭建一个私有笔记服务-Joplin

Joplin 是一款开源的笔记和待办事项应用程序,支持Markdown编辑和多端同步,并且可以私有化部署,对于像我这样习惯使用Markdown写作的人来说,简直是一大福音。在此之前我用过一些云笔记服务,但是随着“降本增效”&#x…

unity学习(38)——创建(create)角色脚本(panel)--EventSystem

1.在scripts文件夹下创建一个脚本CreatePlayerPanel.cs,脚本挂到panel上!给panel加个tag,叫createPanel,脚本内容如下: using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngin…

RabbitMQ-消息队列:发布确认高级

18、发布确认高级 在生产环境中由于一些不明原因,导致 RabbitMQ 重启,在 RabbitMQ 重启期间生产者消息投递失败, 导致消息丢失,需要手动处理和恢复。于是,我们开始思考,如何才能进行 RabbitMQ 的消息可靠投…

如何使用Inno Setup制作Unity构建程序的Windows安装程序

1. 准备 (1)准备好Unity构建的程序集合 必须包括: Data文件夹(xxx_Data) Mono文件夹(MonoBleedingEdge) 打包的应用程序文件(xxx.exe) Unity播放器dll文件&#xff…

瑞_23种设计模式_装饰者模式

文章目录 1 装饰者模式(Decorator Pattern)1.1 介绍1.2 概述1.3 装饰者模式的结构 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 JDK源码解析5 总结5.1 装饰者模式的优缺点5.2 装饰者模式的使用场景5.3 装饰者模式 VS 代理模式 &#x…

Python+Selenium-使用Pillow库进行元素截图

1. Pillow库 Pillow库是Python图像处理的基库,是一个免费开源的第三方库。 通过Python PyPi第三方库官网(https://pypi.org/project/Pillow/#files)下载与平台系统相对应的版本: 下载完成后,进入下载文件的所在位置&…

【LeetCode每日一题】 单调栈的案例 42. 接雨水

这道题是困难,但是可以使用单调栈,非常简洁通俗。 关于单调栈可以参考单调栈总结以及Leetcode案例解读与复盘 42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。 示例 …

ESP8266智能家居(5)——开发APP深入篇

1.代码解析 接下来重点介绍一下逻辑代码 这里面主要是设置mqtt服务器的IP地址和端口号,设置服务器的用户名和登录密码 绑定好订阅主题和发布主题(和8266上的订阅、发布交叉就行) 绑定界面,设置界面标题 绑定6个文本控件 将从mq…

【洛谷题解】B2118 验证子串

题目链接&#xff1a;验证子串 - 洛谷 题目难度&#xff1a;入门 涉及知识点&#xff1a;STL函数 题意&#xff1a; 分析&#xff1a;用一个STL内置的find函数 AC代码&#xff1a; #include<bits/stdc.h> /*find用法&#xff1a;string s1&#xff0c;s2;int as1.f…

设计模式-创建型模式-原型模式

原型模式&#xff08;Prototype Pattern&#xff09;&#xff1a;使用原型实例指定创建对象的种类&#xff0c;并且通过克隆这些原型创建新的对象。原型模式是一种对象创建型模式。原型模式其实就是从一个对象再创建另外一个可定制的对象&#xff0c;而且不需知道任何创建的细节…