【建造者】设计模式:构建复杂对象的艺术

2024-08-31 23:12

本文主要是介绍【建造者】设计模式:构建复杂对象的艺术,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘要

在软件开发中,我们经常会遇到需要创建复杂对象的场景。这些复杂对象可能包含多个属性,并且这些属性的创建过程可能依赖于特定的顺序或者条件。
如果直接使用构造函数来创建这样的对象,可能会导致构造函数过于庞大和复杂,难以维护。这就是建造者设计模式大显身手的地方。

简介

建造者模式是一种创建型设计模式,它提供了一种创建复杂对象的最佳方式。它能够让你分步骤创建复杂对象,并允许你只通过必要的步骤来构建对象,从而使得代码更加清晰和灵活。

为什么需要建造者模式

在平时开发中,创建对象最常用的方式是使用new关键字调用构造函数或者 set 函数来完成。那在什么场景下,这种方式就不适用了,需要使用建造者模式来创建对象呢?

假设对象的属性特别多,当使用构造函数创建对象时,则参数列表太长,影响代码的可读性和易用性
再换一个思路,如果通过构造函数设置必填项通过set方法设置可选项
此时,还是没有用到建造者模式,那如果还需要解决下面3个问题,现在的设计思路就无法满足了。

  • 如果必填项有很多,把这些必填项都放到构造函数中设置,那么构造函数又会出现参数列表很长的问题。如果把必填项通过set函数设置,那校验这些必填项是否已经填写的逻辑就无处安放了。
  • 如果参数之间有一定的依赖关系,按照现在的设计思路,这些参数之间的依赖校验逻辑无处安放。
  • 如果我们希望类对象是不可变对象,即在对象创建好后,就不能再修改对象内部属性值。那就不能在类中暴露set方法。

为了解决这些问题,建造者模式就派上用场了

比如下面这段代码:

我们把校验逻辑放到Builder类中,先创建建造者,并且通过set方法设置建造者的变量值,然后在使用buid()方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象。
此外,我们把ResourcePoolConfig的构造函数设置为私有,这样就只能通过建造者来创建ResourcePoolConfig类对象,且ResourcePoolConfig没有提供任何set方法,这样创建出来的对象就是不可变对象了。

public class ResourcePoolConfig {private String name;private int maxTotal;private int maxIdle;private int minIdle;private ResourcePoolConfig(Builder builder) {this.name = builder.name;this.maxTotal = builder.maxTotal;this.maxIdle = builder.maxIdle;this.minIdle = builder.minIdle;}//我们将Builder类设计成了ResourcePoolConfig的内部类。//我们也可以将Builder类设计成独立的非内部类ResourcePoolConfigBuilder。public static class Builder {private static final int DEFAULT_MAX_TOTAL = 8;private static final int DEFAULT_MAX_IDLE = 8;private static final int DEFAULT_MIN_IDLE = 0;private String name;private int maxTotal = DEFAULT_MAX_TOTAL;private int maxIdle = DEFAULT_MAX_IDLE;private int minIdle = DEFAULT_MIN_IDLE;public ResourcePoolConfig build() {// 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等if (StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}if (maxIdle > maxTotal) {throw new IllegalArgumentException("...");}if (minIdle > maxTotal || minIdle > maxIdle) {throw new IllegalArgumentException("...");}return new ResourcePoolConfig(this);}public Builder setName(String name) {if (StringUtils.isBlank(name)) {throw new IllegalArgumentException("...");}this.name = name;return this;}public Builder setMaxTotal(int maxTotal) {if (maxTotal <= 0) {throw new IllegalArgumentException("...");}this.maxTotal = maxTotal;return this;}public Builder setMaxIdle(int maxIdle) {if (maxIdle < 0) {throw new IllegalArgumentException("...");}this.maxIdle = maxIdle;return this;}public Builder setMinIdle(int minIdle) {if (minIdle < 0) {throw new IllegalArgumentException("...");}this.minIdle = minIdle;return this;}}
}// 这段代码会抛出IllegalArgumentException,因为minIdle>maxIdle
ResourcePoolConfig config = new ResourcePoolConfig.Builder().setName("dbconnectionpool").setMaxTotal(16).setMaxIdle(10).setMinIdle(12).build();

实际上,使用建造者模式创建对象,还能避免对象存在无效状态。
比如,我们定义了一个长方形类,如果不使用建造者模式,采用先创建后set的方式,就会导致在第一个set之后,对象处于无效状态。

Rectangle r = new Rectange(); // r is invalid
r.setWidth(2); // r is invalid
r.setHeight(3); // r is valid

为了避免这种无效状态的存在,我们就需要使用构造函数一次性初始化好所有的成员变量。如果参数过多,则可以考虑使用建造者模式,先设置建造者的变量,然后再一次性的创建对象,让对象一直处于有效状态。

总结

建造者设计模式通过将复杂对象的构建过程与表示分离,提供了一种清晰和灵活的方式来创建复杂对象。它特别适用于对象的创建过程复杂或者对象的创建过程需要根据不同的场景进行定制的情况。通过使用建造者模式,我们可以保持代码的清晰和可维护性,同时提供灵活的对象创建过程。

这篇关于【建造者】设计模式:构建复杂对象的艺术的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125266

相关文章

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

Docker多阶段镜像构建与缓存利用性能优化实践指南

《Docker多阶段镜像构建与缓存利用性能优化实践指南》这篇文章将从原理层面深入解析Docker多阶段构建与缓存机制,结合实际项目示例,说明如何有效利用构建缓存,组织镜像层次,最大化提升构建速度并减少... 目录一、技术背景与应用场景二、核心原理深入分析三、关键 dockerfile 解读3.1 Docke

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

Python利用PySpark和Kafka实现流处理引擎构建指南

《Python利用PySpark和Kafka实现流处理引擎构建指南》本文将深入解剖基于Python的实时处理黄金组合:Kafka(分布式消息队列)与PySpark(分布式计算引擎)的化学反应,并构建一... 目录引言:数据洪流时代的生存法则第一章 Kafka:数据世界的中央神经系统消息引擎核心设计哲学高吞吐

Springboot项目构建时各种依赖详细介绍与依赖关系说明详解

《Springboot项目构建时各种依赖详细介绍与依赖关系说明详解》SpringBoot通过spring-boot-dependencies统一依赖版本管理,spring-boot-starter-w... 目录一、spring-boot-dependencies1.简介2. 内容概览3.核心内容结构4.