第2条 遇到多个构造器参数时要考虑用构建器
静态工厂和构造器有个共同的局限性: 它们都不能很好的扩展到大量的可选参数。
JavaBeans 模式自身有着严重的缺点: 构造过程被分解到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。
JavaBeans模式阻止了把类做成不可变得可能。
Builder模式:不直接生产想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。然后客户端再builder对象上调用类似于setter方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生产不可变对象。
示例:
// Builder Pattern
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
// Required parameters
private final int servintSize;
private final int servings;
Optional parameters - initalized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = bulder.servingSize;
servings = bulder.servings;
calories = bulder.calories;
fat = bulder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
// 调用
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(35).carbohydrate(27).build();
builder 像个构造器一样,可以对其参数强加约束条件。
// A builder for objects of type T
public interface Builder<T> {
public T builder();
}
Builder模式的确也有自身的不足:为了创建对象,必须先创建它的构建器。Builder模式还比重叠构造器模式更加冗长,因此它只在有很多参数时才能使用。
简而言之:如果类的构造器或者静态工厂中具有多个参数,设计这种类时,builder模式就是不错的选择,特别是当大多数参数都是可选的时候。