在《Effective Java》中有提到,遇到多个构造器参数时要考虑使用构建器(Builder模式)。相比于重叠构造器(telescoping constructor)模式和JavaBeans模式,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;
public Person(int id, String name) {
this(id, name, 0);
}
public Person(int id, String name, int age) {
this(id, name, age, "");
}
public Person(int id, String name, int age, String sex) {
this(id, name, age, sex, "");
}
public Person(int id, String name, int age, String sex, String phone) {
this(id, name, age, sex, phone, "");
}
public Person(int id, String name, int age, String sex, String phone, String address) {
this(id, name, age, sex, phone, address, "");
}
public Person(int id, String name, int age, String sex, String phone, String address, String desc) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.phone = phone;
this.address = address;
this.desc = desc;
}
}
传统方式,容易阅读
/**
* 使用JavaBeans模式
*/
public class Person {
//必要参数
private int id;
private String name;
//可选参数
private int age;
private String sex;
private String phone;
private String address;
private String desc;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setAddress(String address) {
this.address = address;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
易于扩展与维护
区分必传参数与可选参数,Builder构造必传参数,剩下的通过链式编程拼接
足够多参数(比如4个,或者更多)的情况下,我们才会去推荐使用它
/**
* 使用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;
}
//可选参数实现链式编程,返回Builder对象
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);
}
}
}
Builder模式使用代码
/**
* 测试使用
*/
public class Test {
public static void main(String[] args) {
Person person = new Person.Builder(1, "张三")
.age(18).sex("男").desc("测试使用builder模式").build();
System.out.println(person.toString());
}
}
/**
* 使用lombok的注解实现build模式
* @Builder默认只能支持实现全参构造方法的builder模式,并且再也无法通过无参构造方法去创建对象
* 我们通过添加@AllArgsConstructor和@NoArgsConstructor,实现支持无参构造创建对象,也支持通过
* builder模式去构建对象
*/
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class Person {
//必要参数,使用lombok的注解帮我们检查不允许为空
@NonNull
private final int id;
@NonNull
private final String name;
//可选参数
private final int age;
private final String sex;
private final String phone;
private final String address;
private final String desc;
}
Builder模式使用代码
/**
* 测试使用
*/
public class Test {
public static void main(String[] args) {
Person person = new Person.Builder.id(1).name("张三")
.age(18).sex("男").desc("测试使用builder模式").build();
System.out.println(person.toString());
}
}