Effective Java中构建器Builder的理解

时间:2022-07-23
本文章向大家介绍Effective Java中构建器Builder的理解,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在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()方法的时候一次性构建出来所需要的对象。