静态工厂方法和构造方法的局限性
当创建Java对象实例时,静态工厂方法和构造方法都有一个共同的局限性:不能友好的扩展到很多可选参数的场景。如关于一个学生的信息:
public class StudentInfo {
private String stuCode; // 学号-必选
private String stuName; // 姓名-必选
private String sex; // 性别-非必选
private Integer age; // 年龄-非必选
private String telephone; // 手机号-非必选
private String address; // 地址-非必选
// 非必选...
}
重载构造函数模式
比较常见,在JDK源码中也随处可见,直接上代码:
public StudentInfo(String stuCode, String stuName) {
this(stuCode, stuName, null);
}
public StudentInfo(String stuCode, String stuName, String sex) {
this(stuCode, stuName, sex, null);
}
public StudentInfo(String stuCode, String stuName, String sex, Integer age) {
this(stuCode, stuName, sex, age, null);
}
public StudentInfo(String stuCode, String stuName, String sex, Integer age, String telephone) {
this(stuCode, stuName, sex, age, telephone, null);
}
public StudentInfo(String stuCode, String stuName, String sex, Integer age, String telephone, String address) {
this.stuCode = stuCode;
this.stuName = stuName;
this.sex = sex;
this.age = age;
this.telephone = telephone;
this.address = address;
}
当想要创建实例时,就选可用的参数列表最短的构造方法:
StudentInfo student = new Student("100", "老王", "男", 18);
总结:重载构造方法模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读。
JavaBeans模式
在这种模式中,调用一个无参数的构造函数来创建对象,然后调用setter方法来设置每个必需的参数和可选参数:
StudentInfo student = new StudentInfo();
student.setStuCode("100");
student.setStuName("老王");
student.setSex("男");
student.setAge(18);
总结:JavaBeans模式创建实例很容易,可读性也很高,但有着严重的缺点,在构造过程中JavaBean可能处于不一致的状态(创建对象和赋值分开了,使用处于不一致状态的对象可能会导致出错)。
建造者builder模式
构建者builder模式能保证像重载构造函数模式那样的安全性,也能保证JavaBeans模式那么好的可读性。实现方法是在所构建的类中写一个静态内部类ExampleBuilder,如下:
public class StudentInfo {
private String stuCode; // 学号-必选
private String stuName; // 姓名-必选
private String sex; // 性别-非必选
private Integer age; // 年龄-非必选
private String telephone; // 手机号-非必选
private String address; // 地址-非必选
public StudentInfo(String stuCode, String stuName, String sex, Integer age, String telephone, String address) {
this.stuCode = stuCode;
this.stuName = stuName;
this.sex = sex;
this.age = age;
this.telephone = telephone;
this.address = address;
}
public static StudentInfoBuilder builder(String stuCode, String stuName) {
return new StudentInfoBuilder(stuCode, stuName);
}
public static class StudentInfoBuilder {
private String stuCode;
private String stuName;
private String sex;
private Integer age;
private String telephone;
private String address;
public StudentInfoBuilder(String stuCode, String stuName) {
this.stuCode = stuCode;
this.stuName = stuName;
}
public StudentInfoBuilder sex(String sex) {
this.sex = sex;
return this;
}
public StudentInfoBuilder age(Integer age) {
this.age = age;
return this;
}
public StudentInfoBuilder telephone(String telephone) {
this.telephone = telephone;
return this;
}
public StudentInfoBuilder address(String address) {
this.address = address;
return this;
}
public StudentInfo build() {
return new StudentInfo(this.stuCode, this.stuName, this.sex, this.age, this.telephone, this.address);
}
}
}
使用简单,可读性高,如下:
StudentInfo student = StudentInfo.builder("100","老王")
.sex("男")
.age(18).build();
总结:如果类的构造方法或静态工厂方法中具有多个参数时,设计这种类时,builder模式是一种不错的选择!(tips:为了创建对象,就必须先创建它的ExampleBuilder,增加了一点额外开销)
扩展:你可能发现了builder模式代码更加冗长,不要担心,它来啦:lombok的@Builder注解,内部原理一模一样,省去了我们的大部分搬砖时间!👍👍👍