「 Java基础-链式调用 」Java开发中如何让你的代码看起来更优雅?试试链式调用?

简介: 我们日常在写业务代码的时候,经常会遇到一种场景,比如一个对象有很多属性,比如用户对象有很多属性:用户名、用户ID、用户性别、用户居住地址、用户工作类型、用户联系方式等等,当我们要构建一个用户对象的时候,就要不断的去`set,get`

一、前言

我们日常在写业务代码的时候,经常会遇到一种场景,比如一个对象有很多属性,比如用户对象有很多属性:用户名、用户ID、用户性别、用户居住地址、用户工作类型、用户联系方式等等,当我们要构建一个用户对象的时候,就要不断的去set,get如下代码所示:

publicclassUser {
privateStringuserName;
privateLonguserId;
privateStringuserSex;
privateStringuserAddress;
privateStringuserJob;
privateStringuserPhone;
privateStringuserBornDate;
}

这种繁琐地set值的代码,会让我们的程序看起来特别臃肿,可读性变差,为了解决这一问题,我们常用的方法一种是创建带参数的构造函数,一种是找个别的类做转换。但是,创建带参数的构造函数时,如果遇到参数太多,这个函数很长看起来很不友好的情况,而且会遇到我有时候创建需要5个,有时候需要2个参数,那就要求实体类要有多个不同参数的构造函数,要不然就在赋予参数的值的时候,直接就按最长的来,大不了用不到的位置set个null值,但是总之还是很不灵活。

二、建造者模式(Builder Pattern)

解决上述问题,我们采用一种比较优雅的方式->链式调用:chained invocation(链式调用)或者Method chaining,这种风格的API设计叫做fluent API或者Fluent interface,常用于Builder Pattern(建造者模式)。链式调用的本质就是在方法里面返回对象/其他来实现连续的调用。

2.1 什么是建造者模式?

建造者模式是一种创建型设计模式, 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。

2.2 建造者模式基本介绍

2.2.1 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。2.2.2 建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

2.3 建造者模式适合应用场景

2.3.1 使用建造者模式可避免 “重叠构造函数 (telescoping constructor)” 的出现。2.3.2 当你希望使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用建造者模式。2.3.3 使用建造者构造组合树或其他复杂对象。

2.4 建造者模式优缺点

2.4.1 优点

1.可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。2.生成不同形式的产品时, 可以复用相同的制造代码。3.单一职责原则。 可以将复杂构造代码从产品的业务逻辑中分离出来。

2.4.2 缺点

由于该模式需要新增多个类,因此代码整体复杂程度会有所增加。

三、链式调用在java源码中的应用

Java中,最常见的链式调用就是StringBuffer、StringBuilder 类中的 append() 方法。如下所示是StringBuilder类的源代码,篇幅所限,提取了部分代码做示例,实际开发中,我们可以通过连续的.append().append()方法来完成字符串的拼接。如下代码所示:StringBuffer、StringBuilder 这两个类都继承自抽象类 AbstractStringBuilder,该抽象类中也有append() 方法。

publicfinalclassStringBuilderextendsAbstractStringBuilderimplementsjava.io.Serializable, CharSequence{
// ... 省略代码 .../*** @throws IndexOutOfBoundsException {@inheritDoc}*/@OverridepublicStringBuilderappend(CharSequences, intstart, intend) {
super.append(s, start, end);
returnthis;
    }
@OverridepublicStringBuilderappend(char[] str) {
super.append(str);
returnthis;
    }
/*** @throws IndexOutOfBoundsException {@inheritDoc}*/@OverridepublicStringBuilderappend(char[] str, intoffset, intlen) {
super.append(str, offset, len);
returnthis;
    }
@OverridepublicStringBuilderappend(booleanb) {
super.append(b);
returnthis;
    }
// ... 省略代码 ...}

四、实现方式

4.1 通过内部类构建

@DatapublicclassUser1 {
// 真正的属性都是不可变的privatefinalintid;
privatefinalStringname;
privatefinalStringjob;
privatefinalStringaddress;
privatefinalDatebirthday;
// 私有构造方法,只被 Builder 类调用privateUser1(Builderbuilder) {
this.id=builder.id;
this.name=builder.name;
this.job=builder.job;
this.address=builder.address;
this.birthday=builder.birthday;
    }
publicstaticclassBuilder {
// 必须参数privateintid;
privateStringname;
privateDatebirthday;
// 可选参数privateStringjob;
privateStringaddress;
publicBuilder(intid, Stringname, Datebirthday) {
this.id=id;
this.name=name;
this.birthday=birthday;
        }
//使用设置好的参数值新建 OperateLog 对象publicUser1build(){
returnnewUser1(this);
        }
// 每个 setter 方法都返回当前的对象,做到链式调用publicBuildersetJob(Stringjob) {
this.job=job;
returnthis;
        }
publicBuildersetAddress(Stringaddress) {
this.address=address;
returnthis;
        }
    }
}

对象内部类的bulider大概分成四部分:

1、 一个简单的内部类,里面的属性和User属性相同;2、 内部类的构造函数;3、 bulid方法,真正核心的一个方法,直接返回一个User实例;4、 属性的set方法,这一部分都是平行的方法;

客户端类调用实例:

//建造者模式只有在调用build()之后才会创建OperateLog对象。User1user1=newUser1.Builder(1,"小明",newDate()).setJob("软件工程师").setAddress("北京").build();

4.2 使用lombok@Builder注解

@Data@AllArgsConstructor@NoArgsConstructor@BuilderpublicclassUser2 {
privateStringname;
privateStringjob;
}

4.3 使用lombok@RequiredArgsConstructor@NonNull注解

@Data@Accessors(chain=true)
@RequiredArgsConstructor(staticName="of")
publicclassUser3 {
@NonNullprivateStringname;
privateStringjob;
}

客户端类分别采用上述3种方式构建对象:

publicclassClient {
publicstaticvoidmain(String[] args) {
// 第一种 建造者模式只有在调用build()之后才会创建User1对象User1user1=newUser1.Builder(1,"小明",newDate()).setJob("软件工程师").setAddress("北京").build();
System.out.println(user1);
// 第二种User2user2=User2.builder().name("小明").job("软件工程师").build();
System.out.println(user2);
// 第三种User3user3=User3.of("小明").setJob("软件工程师");
System.out.println(user3);
    }
}

控制台输出:

User1(id=1, name=小明, job=软件工程师, address=北京, birthday=SunFeb1921:11:12CST2023)
User2(name=小明, job=软件工程师)
User3(name=小明, job=软件工程师)

五、什么情况下适合采用这种链式的方法调用?

上述代码演示的链式调用,实际上是同一个对象的多个方法的连续调用。也就是说,在这个长链中的每个方法返回的都是相同的类型、相同的对象,即当前对象本身。例如,StringBuilderappend方法的连续调用,JSONObject中的accumulateput等方法也可以连续调用。这些被调用的方法都有“构建”的特性,都是用于完善实例对象。使用链式调用代码容易编写,看起来比较简洁也容易阅读和理解。如果被调用的方法返回的类型不同,则不适合链式调用。因为各方法返回的类型被隐藏了,代码不容易理解,另外在调试的时候也是比较麻烦的。

六、总结

6.1 优点

编程性强 、可读性强、代码简洁。

6.2 缺点

不太利于代码调试

七、参考 & 鸣谢

1、学习笔记Java链式调用(方法链)

2、【Java】子类的链式调用

3、java设计模式之建造者模式

感谢前人的经验、分享和付出,让我们可以有机会站在巨人的肩膀上眺望星辰大海!

目录
打赏
0
0
0
0
123
分享
相关文章
基于Java+Springboot+Vue开发的旅游景区管理系统源码+运行
基于Java+Springboot+Vue开发的旅游景区管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的旅游景区管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
33 9
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
34 7
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
53 5
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
基于Java+Springboot+Vue开发的体育场馆预约管理系统源码+运行
基于Java+Springboot+Vue开发的体育场馆预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的体育场馆管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
34 12
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
本文详细讲解了Java开发者如何基于Spring AI Alibaba框架玩转MCP(Model Context Protocol),涵盖基础概念、快速体验、服务发布与调用等内容。重点包括将Spring应用发布为MCP Server(支持stdio与SSE模式)、开发MCP Client调用服务,以及在Spring AI Alibaba的OpenManus中使用MCP增强工具能力。通过实际示例,如天气查询与百度地图路线规划,展示了MCP在AI应用中的强大作用。最后总结了MCP对AI开发的意义及其在Spring AI中的实现价值。
268 9
Java 开发玩转 MCP:从 Claude 自动化到 Spring AI Alibaba 生态整合
本文以原理与示例结合的形式讲解 Java 开发者如何基于 Spring AI Alibaba 框架玩转 MCP。
没有好的学历,Java开发未来的路应该怎么走?
在数字化时代,Java开发者即使没有高学历,也能通过拥抱新兴技术(如大模型应用与鸿蒙系统开发)、积累实战经验、持续学习新技能等途径实现职业突破。从参与开源项目到关注行业动态,再到规划技术专家或管理路线,建立人脉网络并利用教育平台提升能力,开发者可拓宽技术边界,适应日新月异的技术需求,在未来发展中占据一席之地。
Java代码的执行顺序和构造方法
构造方法是类的一种特殊方法,用于初始化新对象。在 Java 中,每个类默认都有一个与类名同名的构造方法,无需返回类型。构造方法不能用 static、final、synchronized、abstract 或 native 修饰。它可以重载,通过不同的参数列表实现多种初始化方式。构造方法在对象实例化时自动调用,若未显式声明,默认提供一个无参构造方法。构造代码块和静态代码块分别用于对象和类的初始化,按特定顺序执行。
70 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等