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

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

相关文章

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St

Java对象转换的实现方式汇总

《Java对象转换的实现方式汇总》:本文主要介绍Java对象转换的多种实现方式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Java对象转换的多种实现方式1. 手动映射(Manual Mapping)2. Builder模式3. 工具类辅助映

Python中判断对象是否为空的方法

《Python中判断对象是否为空的方法》在Python开发中,判断对象是否为“空”是高频操作,但看似简单的需求却暗藏玄机,从None到空容器,从零值到自定义对象的“假值”状态,不同场景下的“空”需要精... 目录一、python中的“空”值体系二、精准判定方法对比三、常见误区解析四、进阶处理技巧五、性能优化

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

一文详解如何从零构建Spring Boot Starter并实现整合

《一文详解如何从零构建SpringBootStarter并实现整合》SpringBoot是一个开源的Java基础框架,用于创建独立、生产级的基于Spring框架的应用程序,:本文主要介绍如何从... 目录一、Spring Boot Starter的核心价值二、Starter项目创建全流程2.1 项目初始化(

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

使用Python和python-pptx构建Markdown到PowerPoint转换器

《使用Python和python-pptx构建Markdown到PowerPoint转换器》在这篇博客中,我们将深入分析一个使用Python开发的应用程序,该程序可以将Markdown文件转换为Pow... 目录引言应用概述代码结构与分析1. 类定义与初始化2. 事件处理3. Markdown 处理4. 转

C#原型模式之如何通过克隆对象来优化创建过程

《C#原型模式之如何通过克隆对象来优化创建过程》原型模式是一种创建型设计模式,通过克隆现有对象来创建新对象,避免重复的创建成本和复杂的初始化过程,它适用于对象创建过程复杂、需要大量相似对象或避免重复初... 目录什么是原型模式?原型模式的工作原理C#中如何实现原型模式?1. 定义原型接口2. 实现原型接口3