遇到多个构造器参数时要考虑用构建器
静态工厂和构造器有个共同的局限性:它们都不能很好的扩展到大量的可选参数
当遇到大量的可选参数时候,一般的处理方式是重载构造方法
重载构造器模式可行,但是当有许多参数的时候,客户端代码很难编写,并且难以阅读
一长串类型相同的参数会导致一些微妙的错误,如果客户端不小心颠倒了其中两个参数的顺序,编译器也不会出错,但是程序在运行的时候回出现一些错误的行为
- 替代方式一
即JavaBean模式,在这种模式下调用一个误餐构造器来创建对象,然后调用setter方法来设置每个必要的参数,以及每个相关的可选参数
Person mPerson = new Person();
mPerson.setName("bob");
mPerson.setAge(10);
mPerson.setProfession("doctor")
...
遗憾的是javaBean模式自身有着很严重的缺点,因为构造过程被分割到好多个set中容易造成线程不安全,导致对象处于不一致的状态
- 替代方式二
既能保证像重叠模式那样的安全,也能保证像javaBeans模式那么好的可读性,这就是builder模式的一种形式
public class NutritionFacts {
private int servingSize ;
private int servings ;
private int calories;
private int fat ;
private int sodium ;
private int carbohydrate;
public static class Builder {
private int servingSize;
private int servings;
private int calories;
private int fat;
private int sodium;
private int carbohydrate;
public Builder(int servingSize, int servings) {
this.servings = servings;
this.servingSize = servingSize;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder carbohydreate(int val){
carbohydrate = val;
return this;
}
public Builder sodium(int val){
sodium = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium =builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
所有的默认参数值都单独放在一个地方,builder的setter方法返回其本身,这样就可以把调用连接起来,客户端代码如下:
NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).
calories(100).sodium(35).build();
这样的客户端代码很同意编写,跟为重要的是,易于阅读,builder模式模拟了具体名字的可选参数
builder像个构造器一样,可以对其参数强加约束条件,builder方法可以检验这些约束条件,将参数从builder拷贝到对象中之后,并在对象域而不是builder域中对他们进行检验,如果违反了任何约束条件,builder方法就应该抛出ILLegalStateException,异常的详细信息应该显示出违反了那个约束条件