为什么要使用构建器(Buildle模式)
静态工厂和构造方法都有共同的局限性:不能很好的扩展到大量的可选参数。
模拟一个场景:
一个Person对象,它有2个必要的参数(name,age),2个可选参数(sex,address),我们来获取它的实例。
1、静态工厂方法实现 - 重叠构造方法
重叠构造方法的缺点:
(1) 出现很多不要的参数却必须设置默认值的的情况。
(2) 重叠构造方法可行,但是当有很多参数时,代码就会很难编写也不容易阅读,使用的时候,必须看清楚每个参数的含义。
public class Person {
// 必要参数
private String name;
private int age;
// 可选参数
private String sex;
private String address;
public Person(String name, int age, String sex, String address) {
this.name = name;
this.age = age;
this.sex = sex;
this.address = address;
}
public static Person normal(String name, int age) {
return new Person(name, age, "男", "北京");
}
public static Person normalAndSex(String name, int age, String sex) {
return new Person(name, age, sex, "北京");
}
public static Person normalAndAddress(String name, int age, String address) {
return new Person(name, age, "男", address);
}
public static Person normalAll(String name, int age, String sex, String address) {
return new Person(name, age, sex, address);
}
}
JavaBean模式实现
- 给一个无参构造方法,然后通过setter方法去设置属性值。
- 这种方式比重叠构造方法更容易创建对象,代码也容易阅读。
public class Person{
// 必要参数
private String name;
private int age;
// 可选参数
private String sex;
private String address;
public Person(){}
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 setAddress(String address){
this.address = address;
}
}
Person person = new Person();
person.setName("李三");
person.setAge(13);
person.setSex("男");
person.setAddress("浙江杭州");
JavaBean的缺点
原文:
JavaBeans模式自身有着很严重的缺点。因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将会导致失败,这种失败与包含错误的代码大相径庭,因此它调试起来十分困难。于此相关的另一点不足在于,JavaBean模式阻止了把类做成不可变的可能,这就需要程序员付出额外的努力来确保它的线程安全。
对上文的理解:
(1) 你创建了一个Person类,提供了无参构造和set/get方法。调用者实例化Person类,但是调用者并不清楚需要为new出来的对象set哪些该有的属性,从而导致就算new出来了对象,这个对象也不能被很好的使用。另外,同时new出来多个对象,每个对象都设置不同的属性,也会导致这几个对象不一致,在你get到未set的属性时,也会出现错误。
(2) 同一个对象,在多线程中,线程A获取这个对象调用这个对象get方法,线程B获取这个对象调用这个对象的set方法,由于线程是谁先抢占CPU谁就先执行,所以会出现你不想要的效果。JavaBean模式并不是一种线程安全的方式。
构建器(Builder)模式
Builder模式:
不直接生成想要的对象,而是利用所有必要的参数调用构造方法或静态工厂,得到一个builder对象。然后再builder对象上调用类似于setter的方法,来设置每个可选的参数。最后调用无参的build方法来生成不可变的对象。
构建器模式的优点:
保证了重叠构造方法模式的安全性,也保证了JavaBeans模式的可读性。
public class Person {
// 必要参数
private String name;
private int age;
// 可选参数
private String sex;
private String address;
public static class Builder {
private String name;
private int age;
// 可选参数设置默认值
private String sex = null;
private String address = null;
// Builder构造方法添加必要的参数
public Builder(String name, int age) {
this.name = name;
this.age = age;
}
public Builder setSex(String sex) {
this.sex = sex;
return this;
}
public Builder setAddress(String address) {
this.address = address;
return this;
}
// build()返回一个对象
public Person build() {
return new Person(this);
}
}
// 在这里可以检查每个参数的合法性
private Person(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.sex = builder.sex;
this.address = builder.address;
}
}
Person person = new Person.Builder("李三", 13)
.setSex("男").setAddress("浙江杭州")
.build();