这条其实没什么好说的,每个程序员都遇到过参数大爆炸的情况,面对大量的可选参数,怎么办?
直接上例子。考虑用一个类表示食品外包装的营养成分标签。这些标签中的有几个域是必须的:每份的分量,每罐的含量以及每份的卡路里,还有超过20个的可选域:总脂肪量,饱和脂肪量,转化脂肪,胆固醇等等,大多数产品在某几个域中都会有非零的值。
Public class NutritionFacts {
private final int servingSize;//ml required
private final int serings;// per container required
private final int calories;//optional
private final int fat;//g optional
private final int sodium;//mg optional
private final int carbonhydrate;//g optional
public NutritionFacts(int servingSize,int serings){
this(servingSize,servings,0);
}
public NutritionFacts(int servingSize,int serings,int calories){
this(servingSize,serings,calories,0);
}
public NutritionFacts(int servingSize,int serings,int calories,fat){
this(servingSize,serings,calories,fat,0);
}
public NutritionFacts(int servingSize,int serings,int calories,fat,sodium){
this(servingSize,serings,calories,fat,sodium,0);
}
public NutritionFacts(int servingSize,int serings,int calories,fat,sodium,carbonhydrate){
this.servingSize = servingSize;
this.serings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbonhydrate = carbonhydrate;
}
}
这种方式是最常见的,缺点也是显而易见的,代码的可读性非常差,而且非常容易出错。
另外一种常见的方式就是JavaBean的方式,先创建实例,再通过set方法初始化,这种方式的缺点也很明显,破坏了创建对象操作的原子性,在构造过程中对象可能处于不一致的状态。
好了,来看一个两全其美的办法吧:
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 carbonhydrate;
public static class Builder {
private final int servingSize;
private final int servings;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbonhydrate = 0;
public Builder(int servingSize,int serving){
this.servingSize = servingSize;
this.servings = serving;
}
public Builder calories(int val){
this.calories = val;
return this;
}
public Builder fat(int val){
this.fat = val;
return this;
}
public Builder carbonhyate(int val){
this.carbonhydrate = val;
return this;
}
public Builder sodium(int val){
this.sodium = 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;
carbonhydrate = builder.carbonhydrate;
}
public static void main(String[] args) {
NutritionFacts cocacola = new NutritionFacts.Builder(240,80).calories(100).sodium(35).carbonhyate(27).build();
}
}
怎么样,是不是两个缺点都避免了,安全性和可读性都很好,当然Builder模式也有它自身的不足,创建构建器会产生一定的开销,对性能要求非常严格的情况下就不一定是最完美的解决方案了。