招聘织梦网站,项目外包平台接活,网页qq游戏怎么登陆,群辉wordpress地址引言
Java语言中的一部经典著作《Effective Java》#xff0c;里面涵盖了78条我们应该熟练的Java编程技巧。
本篇博客是该书学习的系列笔记第一篇。本系列博客不会与书中的78条建议完全匹配。只是以一种读者的身份来记录和总结从书中得到的好的编程建议#xff0c;博客中会…引言
Java语言中的一部经典著作《Effective Java》里面涵盖了78条我们应该熟练的Java编程技巧。
本篇博客是该书学习的系列笔记第一篇。本系列博客不会与书中的78条建议完全匹配。只是以一种读者的身份来记录和总结从书中得到的好的编程建议博客中会明确从书中哪条建议得来的知识。
本博客总结自书中第二条遇到多个构造器参数时要考虑用构建器
构建器的产生
我们知道对象的构建有很多种方式构造器、静态工厂、Setter。
通常最傻瓜式的对象构建方式是通过new关键字调用一个默认的无参构造然后向这个对象中set各种属性。
第二种稍微上点档次的方式是使用构造器。为一个JavaBean创建一个有参构造在new的时候通过有参构造来构建这个bean。
第三种是静态工厂简单的说也是通过一个静态方法来调用一个有参构造来构建对象。
这三种方法貌似都没什么问题。但是设想一下这样的场景
一个JavaBean中有很多属性大于5个这些属性有些是必需的有些是可选的如何来选择构建对象的方式
上述三种方式有参构造、静态工厂、Setter属性依然可以达到场景的要求。但是它们在面对大量可选参数的情况下并不能很好的扩展。原因如下
有参构造或静态工厂需要提供针对可选参数的多个不同参数列表的构造器从而满足不同场景下对可选参数的赋值不同构造器之间参数列表的差别很细微可读性非常差这种方式叫“重叠构造器”。
Setter属性这种方式虽然比较灵活但是有可能有线程安全问题因为在调用构造器与set方法之间对象并未完全构建完毕这个时候如果在多线程的环境下有可能使未完成构建的对象处于一种不安全的状态。这种方式叫“JavaBeans模式”。
总之一句话重叠构造器或重叠静态工厂可以构造出线程安全的JavaBean但是可读性差扩展性不强而JavaBeans模式虽然可读性好灵活但是不具备线程安全性可能发生线程安全问题。
这就产生了新的构造对象的方式构建器。它是“建造者模式”的一种形式同时具备灵活性、线程安全性、可读性等多种优点但是可能也要面临额外的编码量、理解难度、可能存在的性能开销等问题。一般在某个对象含有大量可选参数的情况下使用构建器。
构建器的使用
说了这么多到底构建器是什么我们如何使用构建器呢
首先需要明确一点构建器是用于构建一个对象的。它兼顾了构造器的优点和setter的优点。
客户端使用一个构建器需要完成三件事 1、不直接生成目标对象而是让客户端代码利用所有必需参数调用构造器或静态工厂创建builder对象builder对象用于后续目标对象的创建和赋值工作。 2、客户端在builder对象上调用类似Setter方法来设置每个可选参数。 3、客户端调用无参的builder()方法生成目标对象。 因此客户端代码可以像下面这样
// 客户端代码使用必需参数创建一个builder对象
Student stu new Student.StudentBuilder(10001, 张三, 1, 17)// 必须参数学号、姓名、性别、年龄.headTeacherName(张老师) // 可选参数班主任名称.className(三年一班) // 可选参数班级名称.address(朝阳区-潘家园) // 可选参数家庭住址.specialty(硬笔书法) // 可选参数特长.build(); 可以看到上面的代码中一条语句就完成了对学生对象的创建没有使用setter方法将可选参数的设置与构造器分开因此不会存在线程安全问题可读性也非常强可选参数可以根据不同的场景自由剪裁因此扩展性也非常高。
构建器的创建
和构造器和Setter方法一样我们同样需要在定义JavaBean对象的类中定义一个构建器让它来完成对目标对象的构建工作。
同样构建器的编码工作我们需要注意几个关键步骤 1、构建器实际上是一个静态成员类 2、构建器类中拥有所有目标对象的属性 3、构建器类拥有设置必需参数的构造器和设置每个可选参数的“类似Setter方法” 4、“类Setter方法”返回构建器对象本身 5、构建器有一个无参的build()方法用于创建目标对象 6、目标类有唯一的私有构造器构造器参数就是构建器对象这个构造器的工作就是将参数中的每个属性一 一赋值给目标对象。 和前面客户端创建Student对象对应的Student类代码如下
public class Student {// 必需参数private int stuNo;private String name;private int gender;// 性别0代表女生1代表男生private int age; // // 可选参数private String headTeacherName;// 班主任名称private String address;// 家庭住址private String className;//班级名称private String specialty;//特长private Student(StudentBuilder builder) {this.stuNo builder.stuNo;this.name builder.name;this.gender builder.gender;this.age builder.age;this.headTeacherName builder.headTeacherName;this.address builder.address;this.className builder.className;this.specialty builder.specialty;}/** 用于构建Student对象的构建器类*/public static class StudentBuilder {// 必需private int stuNo;private String name;private int gender;private int age;// 可选private String headTeacherName;// 班主任名称private String address;// 家庭住址private String className;//班级名称private String specialty;//特长public StudentBuilder(int stuNo, String name, int gender, int age) {this.stuNo stuNo;this.name name;this.gender gender;this.age age;}public StudentBuilder headTeacherName(String headTeacherName) {this.headTeacherName headTeacherName;return this;}public StudentBuilder address(String address) {this.address address;return this;}public StudentBuilder className(String className) {this.className className;return this;}public StudentBuilder specialty(String specialty) {this.specialty specialty;return this;}public Student build() {return new Student(this);}}
}
建议给Student添加一个toString()方法并执行一下客户端代码通过构建器创建Student对象并输出它。
可以看到使用构建器的方式确实增加了一部分编码量因此并不是以后所有的情况都是用构建器模式才算好的代码。这种构建器模式通常用于参数较多的情况下。
总结
构建器可以解决因为大量可选参数使用重叠构造器导致客户端代码编码困难、代码可读性差、扩展性不强等缺点同时具备类似Setter的灵活度和可读性。
同时剖析了构建器实现的本质后我们是否也可以简化这种构建器实现方式呢当然可以一个简单的JavaBean让它的有参构造传入所有必需的参数而它的Setter方法将void改为返回当前JavaBean对象不就完全可以达到这种串行构建对象的效果吗书中构建器后半部分的阐述中提到了强加验证的思想但并没有提供代码的实现思路和案例因此在真正使用构建器的时候我们依然可以继续深入的研究构建器的使用方式真正的掌握构建器的使用。
以上就是构建器的学习和使用欢迎大家文末留言讨论。