Effective Java中构建器Builder的理解
2020-04-23 本文已影响0人
夹胡碰
在Effective Java中, 有对构建器的讲解, 看了 java中Builder构建器的理解 之后, 了解了Builder不光只注重了代码优雅, 还注重了对象状态一致性, 以及对后续线程安全的考虑。
使用传统的构造方法
- 缺点: 创建不灵活
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String id;
private String name;
private int age;
public static void main(String[] args) {
User tom = new User("1", "Tom", 20);
}
}
使用JavaBean的 get set方法
- 缺点: 代码繁琐, 不易维护
@NoArgsConstructor
@Data
public class User {
private String id;
private String name;
private int age;
public static void main(String[] args) {
User tom = new User();
tom.setId("1");
tom.setName("tom");
tom.setAge(20);
}
}
使用Builder构建器(Effective Java推荐)
@Builder
public class User {
private String id;
private String name;
private int age;
public static void main(String[] args) {
User tom = User.builder().id("1").name("Tom").age(20).build();
}
}
如果仅仅是为了代码优雅那使用javaBean的set返回this也可以实现和Builder相仿的效果
使用JavaBean的set方法返回this实现类Builder
- 缺点: 代码优雅, 但是不能保证状态一致性, 不方便实现线程安全
public class User {
private String id;
private String name;
private int age;
public User setId(String id) {
this.id = id;
return this;
}
public User setName(String name) {
this.name = name;
return this;
}
public User setAge(int age) {
this.age = age;
return this;
}
public static void main(String[] args) {
// 对象虽然只有一行调用, 但实际是被分到几个调用中, 需要额外付出额外的努力确保线程安全
User tom = new User().setId("1").setName("Tom").setAge(20);
// 同时也无法保证何时是最终态
tom.setName("Jerry");
}
}
下面总结摘自 java中Builder构建器的理解
所以说Builder构建器的真正意义并不是代码优美
Effective Java中写到:遗憾的是,javaBeans模式自身有着很严重的缺点。因为构造过程被分到了几个调用中,在构建过程中JavaBeans可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将会导致失败,这种失败与包含错误的代码大相径庭,因此它调试起来十分困难。与此相关的另一点不足在于,JavaBeans模式阻止了把类做成不可变得可能,这就需要程序员付出额外的努力来确保它的线程安全。
理解了这段意思之后就可以明白,三种创建对象的方式的区别:
-
构造方法:可以保证对象不被修改,但是构建不够灵活,对于传不同参数个数时需要多个构造函数。
-
JavaBeans:构建之后能够灵活的改变对象属性(既是优势也是劣势,需要根据需要来使用),但是赋值过程不是一次性的,也就不是线程安全的。
-
Builder构建器:既能保证构建时的灵活性,还能保证创建对象的一次性。这就需要一个内部类来存储预设置的属性,在调用bulid()方法的时候一次性构建出来所需要的对象。