遇到多个构造器参数时要考虑用构建器
考虑用一个类表示包装食品外面显示的营养成分标签。这些标签中有几个域是必须的:每分的含量,每罐的含量以及每份的卡路里,还有超过20个可选域。对于这样一个类,应该选用那种构造器或者静态方法来编写呢?我们一向习惯采取重叠构造器模式。
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 NutritionFacts(int servingSize,int servings){
this(servingSize,servings,0);
}
public NutritionFacts(int servingSize,int servings,int calories){
this(servingSize,servings,calores,0);
}
public NutritionFacts(int servingSize,int servings,int calories,int fat,int sodium){
this(servingSize,servings,calores,fat,sodium,0);
}
public NutritionFacts(int servingSize,int servings,int calories,int fat,int sodium,int carbohydrate){
this.servingSize=servingSize;
this.servings=servings;
this.calories=calories;
this.fat=fat;
this.sodium=sodium;
this.carbohydrate=carbohydrate;
}
}
这种构造器通常需要许多你不想设置的参数,但是还不得不为他们传递值。在这个例子中,我们就给fat传递了0。如果仅仅6个参数,看起来还不算太糟,问题是随着参数的增加,他们很快就失去了控制。
遇到许多构造起参数的时候,还有第二种替代的办法,即javaBeans模式,在这个模式下,调用一个无参构造器来创造对象,然后调用setter方法来设置每个必须的参数,以及每个相关的可选参数:
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 NutritionFacts(){}
//Setters
public void setServingSize(int val){servingSize=val;}
//........就不多写了
}
遗憾的是,JavaBeans模式自身有着很严重的缺点。因为构造过程被分到几个调用中,在构造过程中JavaBean可能处于非一致的状态。JavaBeans模式阻止了把类做成不可变的可能,这就需要程序员付出额外的努力来确保他的线程安全。
幸运的是,还有第三种代替方法,既能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那么好的可读性。这就是Builder模式的一种形式。不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或者静态工厂),得到一个builder对象。然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用无参的build方法来生成不可变的对象。
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{
private final int servingSize;//必要
private final int servings;//必要
private final int calories=0;//可选
private final int fat=0;//可选
private final int sodium=0;//可选
private final int carbohydrate=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 NutritionFacts build(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
this.servingSize=builder.servingSize;
this.servings=builder.servings;
this.calories=builder.calories;
this.fat=builder.fat;
this.sodium=builder.sodium;
this.carbohydrate=builder.carbohydrate;
}
}
构造的函数
NutritionFacts cacaCola=new NutritionFacts.Builder(240,9).calories(100).sodium(23).build();
网友评论