设计模式导读:建造者模式的细腻之处与编程技巧

笔者的碎碎念

其实之前有写过建造者模式的文章,但是感觉其实写的不怎么样,而且自己也理解的一般,但是阅读一些框架源码发现,这些模式真的蛮重要的,很多框架例如OkHttpRetrofit等等都大量使用了建造者模式以及一些其他的设计模式,于是决定对这些模式进行学习和整理,将写一个专栏来记录自己的的学习记录,你知道的,好记性不如烂笔头,加油!

建造者模式的由来

因 Java 中没有命名参数的概念,当一个类的构造器可选参数太多的时候,代码可读性会变得很差。我们通过一个例子来说明,假设我们有一个连接池的配置类 ConnectionPoolConfig,它包含了多个可选参数,比如 maxConnections(最大连接数)、minConnections(最小连接数)、timeout(超时时间)等。为了支持不同的配置选项,最初可能会使用伸缩式构造器模式或者JavaBeans构造器模式来创建这个对象。

伸缩式构造器模式

public class ConnectionPoolConfig {private int maxConnections;private int minConnections;private int timeout;public ConnectionPoolConfig(int maxConnections, int minConnections, int timeout) {this.maxConnections = maxConnections;this.minConnections = minConnections;this.timeout = timeout;}
...省略ConnectionPoolConfig中的其他构造方法// Getters and setters
}

使用伸缩式构造器模式,我们可能会遇到以下问题:

  • 参数顺序依赖性: 如果某些参数是可选的,并且它们的顺序与构造函数中的参数顺序不匹配,那么我们就不得不在构造对象时填充未使用的默认值,比如:

    ConnectionPoolConfig config = new ConnectionPoolConfig(10, 5, 0); // timeout 默认为 0
    
  • 参数类型相似性: 如果两个参数类型相似(比如都是整数),在构造对象时容易搞错参数的顺序,这可能会导致严重的错误。

JavaBeans构造器模式

然后,我们针对这些进行改进,有了后来的JavaBeans构造器模式。

public class ConnectionPoolConfig {private int maxConnections;private int minConnections;private int timeout;public ConnectionPoolConfig() {// Empty constructor}// Setterspublic void setMaxConnections(int maxConnections) {this.maxConnections = maxConnections;}public void setMinConnections(int minConnections) {this.minConnections = minConnections;}public void setTimeout(int timeout) {this.timeout = timeout;}
...省略// Getters
}

使用JavaBeans构造器模式,虽然解决了参数顺序依赖性的问题,但引入了新的问题: 

  • 对象状态不一致性: 构建对象需要多次调用不同的 setter 方法,这可能会导致对象在构造过程中处于不一致的状态。例如,如果某个字段在设置之前被访问,可能得到不完整或不正确的对象状态。 

建造者模式

于是,建造者模式(Builder Pattern)应运而生。

建造者模式在这些问题的基础上提供了更加灵活和安全的对象构建方式:

public class ConnectionPoolConfig {private final int maxConnections;private final int minConnections;private final int timeout;private ConnectionPoolConfig(Builder builder) {this.maxConnections = builder.maxConnections;this.minConnections = builder.minConnections;this.timeout = builder.timeout;}// Getterspublic static class Builder {private int maxConnections;private int minConnections;private int timeout;public Builder() {// 默认值或者空构造器}public Builder maxConnections(int maxConnections) {this.maxConnections = maxConnections;return this;}public Builder minConnections(int minConnections) {this.minConnections = minConnections;return this;}public Builder timeout(int timeout) {this.timeout = timeout;return this;}public ConnectionPoolConfig build() {return new ConnectionPoolConfig(this);}}
}

优点: 

  • 链式调用: 使用建造者模式,可以使用链式调用来设置对象的各个属性,清晰地表达出构建对象的步骤和顺序。
ConnectionPoolConfig config = new ConnectionPoolConfig.Builder().maxConnections(10).minConnections(5).timeout(0).build();

  • 对象不可变性: 在建造者模式中,可以将对象设计为不可变的(Immutable),一旦构建完成后,对象的状态不可修改,保证了对象的线程安全性和一致性。
  • 消除对象状态不一致性问题: 建造者模式通过在最终构建之前保持对象状态的一致性,避免了JavaBeans模式中可能出现的对象状态不一致性问题。
  • 易于解耦:将产品本身与产品创建过程进行解耦,可以使用相同的创建过程来得到不同的产品。也就说细节依赖抽象。
  • 易于精确控制对象的创建:将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰
  • 易于拓展:增加新的具体建造者无需修改原有类库的代码,易于拓展,符合“开闭原则“。

每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。 

模式原理

使用场景 

建造者模式适用于需要创建复杂对象(对象有多个部分,且构建过程复杂)的场景,或者需要创建多个相似对象(只有部分属性不同)的场景。它有效地解决了伸缩式构造器模式和JavaBeans构造器模式存在的问题,并提供了一种更加优雅和灵活的解决方案。你经常能在Android看到一些常见的技术框架中都使用了该模式,例如OkHttp框架中就有它的大量使用。关于OkHttp我也有文章进行分析,如果你感兴趣,可以去看看OkHttp中是如何使用建造者模式的->【传送门】。

使用 

  1. 构造者的创建:客户端通过创建一个具体的建造者对象(如 Builder),并使用链式调用来设置产品的各个属性
     

    ConnectionPoolConfig config = new ConnectionPoolConfig.Builder().maxConnections(10).minConnections(5).timeout(30).build();
    
  2. 属性设置

    每次调用建造者的设置方法(如 maxConnectionsminConnectionstimeout)时,建造者内部会更新自己的状态,以便在构建最终产品时使用。
  3. 构建产品

    最终调用 build() 方法时,建造者将使用其内部状态来实例化并初始化产品对象 ConnectionPoolConfig,并返回给客户端。

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

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

相关文章

人脸处理——人脸换脸基础算法探索与应用测试指南

人工智能(AI)彻底改变了我们生活的许多方面,而这项技术的应用之一就是AI换脸工具。这些工具使用先进的计算机视觉技术和深度学习算法,例如生成对抗网络 (GAN),在照片或视频中将一个人的脸与另一个人的脸交换。 1. Dee…

六西格玛培训公司:解锁成功之门,让企业与个人共赴“嗨”途

在竞争激烈的21世纪,六西格玛培训公司手握一把神奇的钥匙,帮助企业及个人轻松开启成功的大门。 对企业来说: 产品质量飞跃:不再是偶尔的精品,而是每个产品都如同精雕细琢的艺术品,吸引无数顾客争相购买。…

web3.0链游农民世界开发搭建0撸狼人杀玩法模式定制开发

随着区块链技术的飞速发展,Web3.0时代的链游已成为游戏行业的新宠。本文将介绍一款基于Web3.0的链游——农民世界,如何定制开发0撸狼人杀玩法模式,以及该模式的专业性、深度思考和逻辑性。 一、背景介绍 农民世界是一款以农业为主题的链游…

嵌入式系统基础

嵌入式系统基础主要包括以下几个方面: 1、定义: 嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。它由硬件和软件组成&#xff0…

.NET 通过UserInit键实现Windows权限维持

01阅读须知 此文所节选自小报童《.NET 内网实战攻防》专栏,主要内容有.NET在各个内网渗透阶段与Windows系统交互的方式和技巧,对内网和后渗透感兴趣的朋友们可以订阅该电子报刊,解锁更多的报刊内容。 02基本介绍 本文内容部分节选自小报童…

Spring Boot 学习第七天:动态代理机制与Spring AOP

1 概述 在Java的世界中,实现AOP的主流方式是采用动态代理机制,这点对于Spring AOP也一样。代理机制的主要目的就是为其他对象提供一种dialing以控制对当前对象的访问,用于消除或缓解直接访问对象带来的问题。通过这种手段,一个对象…

【Bugku CTF】web解题记录

记录我在Bugku CTF靶场中做的比赛真题,便于自己以后的复习 1.my-first-sqli 进入此关卡,发现参数有username和password 我们尝试在username上注入数字型、字符型参数,后面发现注入字符型的单引号的有报错语句,我们在username上注…

【服务器08】之【游戏框架】之【加载主角】

首先简单了解一下帧率 FixedUpdate( ) > Update( ) > LateUpdate( ) 首先FixedUpdate的设置值 默认一秒运行50次 虽然默认是0.02秒,但FiexedUpdate并不是真的0.02秒调用一次,因为在脚本的生命周期内,FixedUpdate有一个小循环&…

大学计算机

项目一 了解计算机 1.1 了解计算机的诞生及发展阶段 1.2 认识计算机的特点、应用和分类 1.计算机的特点 1. 计算机的特点 2.计算机的应用 3.计算机的分类 4.数量单位 1.3 了解计算机操作系统的概念、功能与种类 1.操作系统概念 2.操作系统的作用 1&#xff0e…

感应电机转差速度估算

在感应电机矢量控制中,需要计算出感应电机的机械转差速度(同步速度和转子速度之间的差)。以下方程描述了感应电机磁场定向控制 (FOC) 中转差速度值的关系: 如果我们保持转子磁通恒定,并且 d 轴与转子磁通参考系对齐&am…

基于Java医院门诊互联电子病历管理信息系统设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…

ubuntu 18.04 server源码编译安装freeswitch 1.10.7支持音视频通话、收发短信——筑梦之路

软件版本说明 ubuntu版本18.04:https://releases.ubuntu.com/18.04.6/ubuntu-18.04.6-live-server-amd64.iso freeswitch 版本1.10.7:https://files.freeswitch.org/freeswitch-releases/freeswitch-1.10.7.-release.tar.gz spandsp包:https:…

学习笔记——路由网络基础——路由汇总(路由聚合)

九、路由汇总(路由聚合) 1、路由汇总背景 子网划分、VLSM解决了地址空间浪费的问题,但同时也带了新的问题,路由表中的路由条目数量增加。为减少路由条目数量可以使用路由汇总。 对于一个大规模的网络来说,路由器或其他具备路由功能的设备势…

C#的Switch语句2(case后的值与模式匹配)

文章目录 switch语法结构case具体的值枚举值字符串const关键字 如果没有匹配的值default语句不一定要在最后 模式匹配与C的差异-case穿透(Fall-through)下一篇文章 switch语法结构 基础的语法结构,在上一篇文章已经写了,具体请看…

git 初基本使用-----------笔记

Git命令 下载git 打开Git官网(git-scm.com),根据自己电脑的操作系统选择相应的Git版本,点击“Download”。 基本的git命令使用 可以在项目文件下右击“Git Bash Here” ,也可以命令终端下cd到指定目录执行初始化命令…

6.20作业

1.已知网址www.hqyj.com截取出网址的每一个部分(要求,该网址不能存入文件中) echo www.hqyj.com | cut -d "." -f "1,2,3" 2.整理思维导图 3.将配置桥接网络的过程整理成文档,发csdn

条码工具 Dynamic Web TWAIN HTML5 版本的工作原理

Dynamic Web TWAIN 是一个专为Web应用程序设计的TWAIN扫描识别控件。你只需在TWAIN接口写几行代码,就可以用兼容TWAIN的扫描仪扫描文档或从数码相机/采集卡中获取图像。然后用户可以编辑图像并将图像保存为多种格式,用户可保存图像到远程数据库或者Share…

轻松搞定Python List 列表必备方法大全!

更多Python学习内容:ipengtao.com 在 Python 编程中,list(列表)是一种非常重要且常用的数据结构。列表可以存储不同类型的元素,并且提供了许多方便的内置方法来操作和处理这些元素。本文将详细介绍 Python 中 list 列表…

【笔记】HashMap的头插死循环问题

HashMap头插死循环是指在JDK1.7中,多线程环境下,HashMap进行扩容时由于多个线程一起执行扩容,可能会导致某一结点被错误插入头部并形成一个循环链表。 发生死循环的源码如下: // hashmap由数组链表构成 void transfer(Entry[] ne…

Android 13 修改系统导航默认值

Android 13 原生系统上,设置-系统-手势-系统导航 菜单,可以修改系统导航方式。 手势导航: 三按钮导航: adb 获取当前导航方式,手势导航 是 2 ,三按钮导航是 0 。 settings get secure navigation_mode 修…