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

在这里插入图片描述

建造者设计模式

建造者设计模式(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://www.hqwc.cn/news/493476.html

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

相关文章

Leetcode刷题笔记题解(C++):6. Z 字形变换

思路:遍历时候需要更新步进长度 到达0行的时候步进长度为1;到达最后一行numRows-1行的时候步进长度为-1;代码如下所示: class Solution { public:string convert(string s, int numRows) {//如果字符串长度为1或者所给行数为1 …

[c++] char * 和 std::string

1 char * 和 std::string 的区别 char * 字符串是常量字符串,不能修改;std::string 指向的字符串可以修改 实例代码如下图所示,s1 和 s2 均是常量字符串,字符串常量保存在只读数据区,是只读的,不能写&…

Unity类银河恶魔城学习记录7-9 P75 Saw spin sword源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Sword_Skill_Controller.cs using System.Collections; using System.Col…

QT信号槽实现分析

1.宏定义 qt中引入了MOC来反射,编译阶段变成 MOC–>预处理–>编译–>汇编–>链接 1-1、Q_OBJECT 这个宏定义了一系列代码,包括元对象和处理的函数 #define Q_OBJECT \public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static c…

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候,问到许多年轻的Android开发他所会的设计模式是什么,基本上都会提到单例模式,但是对单例模式也是一知半解,在Android开发中我们经常会运用单例模式,所以我们还是要更了解单例模式才对…

汇编语言与接口技术实践——秒表

1. 设计要求 基于 51 开发板,利用键盘作为按键输入,将数码管作为显示输出,实现电子秒表。 功能要求: (1)计时精度达到百分之一秒; (2)能按键记录下5次时间并通过按键回看 (3)设置时间,实现倒计时,时间到,数码管闪烁 10 次,并激发蜂鸣器,可通过按键解除。 2. 设计思…

音视频技术-电脑连接调音台时交流声的产生与消除

当电脑(笔记本/台式机)声卡通过音频线与调音台(或扩音机)连接时,能听到“交流声”。有时很轻微,有时很明显,甚至干扰正常的演讲或发言。 很多时候,我们在台上演讲时,都会…

模拟、排序(归并排序)算法

模拟、排序算法 一、模拟例题1、错误票据题目信息思路题解 2、回文日期题目信息思路方法一:暴力做法方法二:优化解法 题解方法一:暴力求解方法二:优化解法 二、排序例题1、归并排序题目信息思路题解 一、模拟 例题 1、错误票据 …

springboot222学生网上选课系统的设计与实现

学生网上选课系统的设计与实现 摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统学生选课信息管理难度大&…

MDC500-16-ASEMI工业电机专用MDC500-16

编辑:ll MDC500-16-ASEMI工业电机专用MDC500-16 型号:MDC500-16 品牌:ASEMI 正向电流(Id):500A 反向耐压(VRRM):1600V 正向浪涌电流:600A 正向电压&a…

MATLAB Function转C代码实战

文章目录 前言1. 准备工作2. 使用MATLAB Coder2.1 确定输入输出的类型2.2 MATLAB Coder过程 3. 代码调整和优化4. 编译和测试5. 性能分析和优化结语 前言 在科学与工程领域,MATLAB(Matrix Laboratory)是一种广泛使用的高级技术计算软件&…

【C之·预处理器】

系列文章目录 文章目录 前言一、预处理指令1. #line的用法1.1 概述 2. #error2.1 概述 二、示例1. #line2. #error 总结 前言 C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已&#x…

从0到1入门C++编程——08 函数模板和类模板

文章目录 函数模板1.函数模板基本语法2.函数模板使用的注意事项3.函数模板案例——数组排序4.普通函数和函数模板的区别5.普通函数和函数模板的调用规则6.模板的局限性 类模板1.类模板2.类模板和函数模板的区别3.类模板中成员函数创建时机4.类模板对象做函数参数5.类模板与继承…

飞机订票系统

飞机订票系统 获取源码——》公主号:计算机专业毕设大全

Sora背后团队大揭秘!天才00后?

现在世界上最受关注的技术团队是哪一支? Sora 团队,已经来到聚光灯中心。 不仅项目负责人评论区被挤爆,成了𝕏最火“景点” 。 当 OpenAI 出手发布 Sora 之后,给人一种降维打击的感觉 —— 效果和之前的技术相比高出…

「哈哥赠书活动 - 48期」-『商业分析思维与实践:用数据分析解决商业问题宣传文案』

⭐️ 赠书 - 《商业分析思维与实践》 ⭐️ 内容简介 本书以业务为导向,详细地讲解了如何通过大数据分析来解决商业问题。其目的在于运用大数据分析思维,帮助读者把学术知识应用于真实的业务场景,解决实际的业务问题。本书基于业务问题&#x…

应急响应实战笔记03权限维持篇(3)

0x00 前言 攻击者在获取服务器权限后,会通过一些技巧来隐藏自己的踪迹和后门文件,本文介绍Linux下的几种隐藏技术。 0x01 隐藏文件 Linux 下创建一个隐藏文件:touch .test.txt touch 命令可以创建一个文件,文件名前面加一个 点…

MYSQL--(1.存储引擎 *2.事务*)

一 存储引擎: 1.介绍 1>在数据库管理系统当中通过使用数据引擎来实现数据的增删改,查询 2>不同的存储引擎提供的有不同的存储机制,索引技巧等功能 MYSQL的核心,就是存储引擎 3>同样的,用户也可以根据自己的需要进行选择,更改自己需要…

学习 LangChain 的 Passing data through

学习 LangChain 的 Passing data through 1. Passing data through2. 示例 1. Passing data through RunnablePassthrough 允许不改变或添加额外的键来传递输入。这通常与 RunnableParallel 结合使用,将数据分配给映射中的新键。 RunnablePassthrough() 单独调用&…

【GAD】DOMINANT个人解读/学习

SDM2019,这是一篇图异常检测领域的经典方法. 问题定义 在本文中,我们使用手写体来表示集合(例如, V \mathcal{V} V),粗体小写字母(例如, x \mathbf{x} x)来表示向量&…