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

news/发布时间2024/5/15 11:21:52

在这里插入图片描述

建造者设计模式

建造者设计模式(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.bcls.cn/IicZ/3575.shtml

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

相关文章

学生成绩管理系统(C语言课设 )

这个学生成绩管理系统使用C语言编写,具有多项功能以方便管理学生信息和成绩。首先从文件中读取数据到系统中,并提供了多种功能(增删改查等)选项以满足不同的需求。 学生成绩管理系统功能: 显示学生信息增加学生信息删除学生信息…

Jmeter学习系列之六:阶梯加压线程组Stepping Thread Group详解

性能测试中,有时需要模拟一种实际生产中经常出现的情况,即:从某个值开始不断增加压力,直至达到某个值,然后持续运行一段时间。 在jmeter中,有这样一个插件,可以帮我们实现这个功能,这个插件就是:Stepping Thread Group 1、下载配置方法 1.1.下载配置 插件下载地址:…

一文读懂:AWS 网络对等互连(VPC peering)实用操作指南

VPC peering connection-网络对等互连在您的 Atlas VPC 和云提供商的 VPC 之间建立私有连接。该连接将流量与公共网络隔离以提高安全性。本篇文章有VPC peering的操作指南以及价格等信息。如还有疑问请联系我们MongoDB的销售,客户成功经理或解决方案架构师。 1 使用…

学习总结22

解题思路 简单模拟。 代码 #include <bits/stdc.h> using namespace std; long long g[2000000]; long long n; int main() {long long x,y,z,sum0,k0;scanf("%lld",&n);for(x1;x<n;x)scanf("%lld",&g[x]);for(x1;x<n;x){scanf(&qu…

物理备份的方式

完全备份恢复流程 停止数据库清理环境重演回滚&#xff0d;&#xff0d;> 恢复数据修改权限启动数据库 1.关闭数据库&#xff1a; [rootmysql-server ~]# systemctl stop mysqld [rootmysql-server ~]# rm -rf /var/lib/mysql/* //删除所有数据// [rootmysql-server ~]# …

unity Aaimation Rigging使用多个约束导致部分约束失去作用

在应用多个约束时&#xff0c;在Hierarchy的顺序可能会影响最终的效果。例如先应用了Aim Constraint&#xff0c;然后再应用Two Bone Constraint&#xff0c;可能会导致Two Bone Constraint受到Aim Constraint的影响而失效。因此&#xff0c;在使用多个约束时&#xff0c;应该仔…

【JVM】Java中SPI机制

打破双亲委派模型中提到SPI和JDBC相关内容&#xff0c;那么是如何打破双亲委派模型呢?本文进行一个讲解&#xff0c;在开始讲解之前&#xff0c;我们需要先了解Java中的SPI机制 是什么 SPI 全称Service Provider Interface&#xff0c;是 Java 提供的一套用来被第三方实现或…

Docker vs VM

关于应用程序的托管和开发&#xff0c;市场中的技术和产品琳琅满目。对比 Docker 和 VM&#xff0c;如何取舍&#xff1f;这主要由自身团队的因素决定&#xff0c;在选择 Docker 的情况下&#xff0c;你需要保证程序可在容器和虚拟机中运行。另外&#xff0c;成本和易用性也是重…

python毕设选题 - 大数据商城人流数据分析与可视化 - python 大数据分析

文章目录 0 前言课题背景分析方法与过程初步分析&#xff1a;总体流程&#xff1a;1.数据探索分析2.数据预处理3.构建模型 总结 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到…

ChatGPT 是什么

文章目录 一、ChatGPT 是什么二、ChatGPT的发明者三、ChatGPT的运作方式四、ChatGPT的技术五、ChatGPT的优势六、ChatGPT的局限性七、ChatGPT的应用八、ChatGPT的未来九、总结 一、ChatGPT 是什么 OpenAI的ChatGPT&#xff0c;即Chat Generative Pre-Trained Transformer&…

[算法沉淀记录] 排序算法 —— 归并排序

排序算法 —— 归并排序 算法介绍 归并排序是一种分治算法&#xff0c;由约翰冯诺伊曼在1945年发明。它的工作原理是将未排序的列表划分为n个子列表&#xff0c;每个子列表包含一个元素(包含一个元素的列表被认为是有序的)&#xff0c;然后重复合并子列表以生成新的有序子列表…

C#实用开发(14)--高清晰度字体和窗体分辨率问题。

新建winform程序是&#xff0c;又是会感觉到字体清晰度不够高。还有一种现象就是分辨率的问题&#xff0c;我们平常在自己的电脑开发是用125百分比的分辨率&#xff0c;实际部署的工控机是100&#xff0c;这就会导致分辨率不一致的问题。 可以通过新建应用程序清单&#xff0c;…

jetson nano——安装archiconda

目录 1.archiconda3我在这提供了下载链接&#xff0c;点解下面链接即可1.看好文件所在位置&#xff0c;如果装错了&#xff0c;那么环境变量的路径自己进行相应的修改。2.添加环境变量 2.可能部分伙伴输入一些激活&#xff0c;啥的命令激活不了&#xff0c;那么输入下面这些代码…

Redis实现滑动窗口限流

常见限流算法 固定窗口算法 在固定的时间窗口下进行计数&#xff0c;达到阈值就拒绝请求。固定窗口如果在窗口开始就打满阈值&#xff0c;窗口后半部分进入的请求都会拒绝。 滑动窗口算法 在固定窗口的基础上&#xff0c;窗口会随着时间向前推移&#xff0c;可以在时间内平滑控…

ClickHouse 指南(三)最佳实践 -- 稀疏主索引

在ClickHouse主索引的实用介绍 ClickHouse release 24.1, 2024-01-30 1、简介 在本指南中&#xff0c;我们将深入研究ClickHouse索引。我们将详细说明和讨论: ClickHouse中的索引与传统的关系数据库管理系统有何不同ClickHouse是如何构建和使用表的稀疏主索引的什么是在Clic…

潇洒郎:2024 IDEA、Pycharm获取最新激活码获取方式

IDEA获取最新激活码 https://idea.javatiku.cn/ 手机打开&#xff0c;看到验证码&#xff0c;30分钟有效&#xff0c;输入验证码 获取到最新激活码

【C++私房菜】面向对象中的多重继承以及菱形继承

文章目录 一、多重继承1、多重继承概念2、派生类构造函数和析构函数 二、菱形继承和虚继承2、虚继承后的构造函数和析构函数 三、has-a 与 is-a 一、多重继承 1、多重继承概念 **多重继承&#xff08;multiple inheritance&#xff09;**是指从多个直接基类中产生派生类的能力…

Jmeter基础(2) 目录介绍

目录 Jmeter目录介绍bin目录docsextrasliblicensesprintable_docs Jmeter目录介绍 在学习Jmeter之前&#xff0c;需要先对工具的目录有些了解&#xff0c;也会方便后续的学习 bin目录 examplesCSV目录中有CSV样例jmeter.batwindow 启动文件jmeter.shMac/linux的启动文件jmete…

基于Mapbox展示GDAL处理的3D行政区划展示实践

目录 前言 一、Gdal数据处理 1、数据展示 2、Java数据转换 二、Mapbox可视化 1、定义Mapbox地图 2、地图初始化 3、创建地图 三、界面优化 1、区域颜色设置 2、高度自适应和边界区分 3、中文标注 总结 前言 最近有遇到一个需求&#xff0c;用户想在地图上把行政区划…

十、线性代数二-线性相关

目录 1、线性相关的概念&#xff1a; 2、线性相关的代数表示&#xff1a; 3、线性相关的判断方法&#xff1a; 理解&#xff1a;线性相关指的是 向量组&#xff08;α1&#xff0c;α2&#xff0c;α3&#xff0c;...&#xff09;的 秩是 小于 k 的元数的&#xff0c;即齐次…
推荐文章