1. 三种对象创建模式

当我们要创建一个类的对象并设定对应属性时,一般有三种方法

  1. 重叠构造器模式

在这种模式下,提供第一个只有必要参数的构造器,第二个构造器只有一个可选参数,第三个有两个可选参数,依次类推,最后一个包含所有的参数,例如

  1. public class Person {
  2. //必要参数
  3. private final int id;
  4. private final String name;
  5. //可选参数
  6. private final int age;
  7. private final String sex;
  8. private final String phone;
  9. private final String address;
  10. private final String desc;
  11. public Person(int id, String name) {
  12. this(id, name, 0);
  13. }
  14. public Person(int id, String name, int age) {
  15. this(id, name, age, "");
  16. }
  17. public Person(int id, String name, int age, String sex) {
  18. this(id, name, age, sex, "");
  19. }
  20. public Person(int id, String name, int age, String sex, String phone) {
  21. this(id, name, age, sex, phone, "");
  22. }
  23. public Person(int id, String name, int age, String sex, String phone, String address) {
  24. this(id, name, age, sex, phone, address, "");
  25. }
  26. public Person(int id, String name, int age, String sex, String phone, String address, String desc) {
  27. this.id = id;
  28. this.name = name;
  29. this.age = age;
  30. this.sex = sex;
  31. this.phone = phone;
  32. this.address = address;
  33. this.desc = desc;
  34. }
  35. }
显然, 过多的构造器会使得代码非常臃肿,同时在创建对象时很容易因为参数列表的顺序错误导致难以察觉的问题。  
  1. JavaBean

调用一个无参构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数,这个可以配合@Data注解来简化,例如

@Data // 自动生成getter和setter
public class Person {
    //必要参数
    private int id;
    private String name;
    //可选参数
    private int age;
    private String sex;
    private String phone;
    private String address;
    private String desc;
}
但是这样的话,就需要好几步来分别设置,无法一口气设置完。
  1. 构建器模式

还有第三种替代方法,即能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那样的可读性,还能一口其设置完,这就是构建起模式(又称Builder模式)。它并不直接生成想要的对象,而是让客户端利用所有必要的参数调用构建器(或叫静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似setter的方法,来设置每个相关的可选参数。 最后,客户端调用无参的builder方法来生成不可变的对象。这个builder是它构建类的静态成员类

public class Person {
    //必要参数
    private final int id;
    private final String name;
    //可选参数
    private final int age;
    private final String sex;
    private final String phone;
    private final String address;
    private final String desc;

    private Person(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.age = builder.age;
        this.sex = builder.sex;
        this.phone = builder.phone;
        this.address = builder.address;
        this.desc = builder.desc;
    }

    public static class Builder {
        //必要参数
        private final int id;
        private final String name;
        //可选参数
        private int age;
        private String sex;
        private String phone;
        private String address;
        private String desc;

        public Builder(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public Builder age(int val) {
            this.age = val;
            return this;
        }

        public Builder sex(String val) {
            this.sex = val;
            return this;
        }

        public Builder phone(String val) {
            this.phone = val;
            return this;
        }

        public Builder address(String val) {
            this.address = val;
            return this;
        }

        public Builder desc(String val) {
            this.desc = val;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }
}

2. @Builder

lombok的@Builder实际上是构建者模式的一个变种。当一个类(Person)加上了@Builder注解后,就多了一个静态内部类PersonBuilder,People调用静态方法builder()生成PersonBuilder对象,PersonBuilder对象可以使用“.属性名(属性值)”的方式进行属性设置,再调用build()方法就生成了对应的Person对象
它属于lombok的依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
     <optional>true</optional>
</dependency>

Perosn类

import lombok.Builder;
import lombok.Data;

@Data  // 生成getter、setter,重写 hashcode、equals
@Builder
public class Person {
    private String name;
    private String sex;
    private int age;
}
然后就可以优雅的使用bulider模式来优雅地创建特定属性值的对象:
public class TestBuilder {

    @Test
    public void testBuilderAnnotation(){
        People luoTianyi = Person.builder()
                .sex("female")
                .age(23)
                .name("LuoTianyan")
                .build();


        System.out.println(luoTianyi.toString());
        //Person(name=LuoTianyan, sex=female, age=23)

        People people = new Person("LuoTianyi","female",23);
        System.out.println(luoTianyan.equals(people));
        //true  
    }

}