public class NutritionFacts {
private final int servingSize; //(ml)
private final int servings; //(per container)
private final int calories; //
private final int fat; //(g)
private final int sodium; //(mg)
private final int carbohydrate; //(g)
public NutritionFacts (int servingSize,int servings) {
this(servingSize,servings,0);
}
public NutritionFacts (int servingSize,int servings,int calories) {
this(servingSize,servings,calories,0);
}
public NutritionFacts (int servingSize,int servings,int calories,int fat) {
this(servingSize,servings,calories,fat,0);
}
public NutritionFacts (int servingSize,int servings,int calories,int fat,int sodium) {
this(servingSize,servings,calories,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;
}
}
例如 :NutritionFacts pork=new NutritionFacts(500,1,10);
重叠构造器模式可行,但是当有许多参数的时候,客户端代码会很难编写,并且仍然较难以阅读。
当有一连串相同类型的参数的时候,会很容易颠倒其中一些参数的顺序,而编译器却不会出错。
所以会通常会想到用JavaBean模式来替代。
public class NutritionFacts {
private int servingSize=-1; //(ml)
private int servings=-1; //(per container)
private int calories=0; //
private int fat=0; //(g)
private int sodium=0; //(mg)
private int carbohydrate=0; //(g)
public NutritionFacts () {}
public void setServingSize(int servingSize) {this.servingSize = servingSize;}
public void setServings(int servings) {this.servings = servings;}
public void setCalories(int calories) {this.calories = calories;}
public void setFat(int fat) {this.fat = fat;}
public void setSodium(int sodium) {this.sodium = sodium;}
public void setCarbohydrate(int carbohydrate) {this.carbohydrate = carbohydrate;}
}
但是,JavaBean模式自身有着很严重的缺点。因为构造过程被分到了几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。JavaBean模式还存在另一点不足,JavaBean模式阻止了把类做成不可变的可能(见第15条,后期会加链接),这就需要程序员付出额外的努力来确保它的线程安全。如何能够既像重叠构造器那样的安全,又能保证像JavaBean模式那么好的可读性?
Builder模式就能满足这两点需求。
public class NutritionFacts {
private int servingSize=-1; //(ml)
private int servings=-1; //(per container)
private int calories=0; //
private int fat=0; //(g)
private int sodium=0; //(mg)
private int carbohydrate=0; //(g)
public static class Builder{
//Required parameters
private final int servingSize;
private final int servings;
//Optional parameters - initialized 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 calories) {
this.calories = calories;
return this;
}
public Builder fat(int fat) {
this.fat = fat;
return this;
}
public Builder carbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
return this;
}
public Builder sodium(int sodium) {
this.sodium = sodium;
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;
}
}
NutritionFacts nutritionFacts=new NutritionFacts.Builder(240,8)
.calories(100)
.sodium(35)
.carbohydrate(27).build();
Builder方式让客户端代码很容易编写,也更加易于阅读。
但是Builder模式也有它自身的不足。为了创建对象,必须先创建builder的构建器。在某些十分注重性能的情况下,它可能就是个问题了。
如果类的构造器或者静态工厂中具有多个参数,设计这种类时,Builder模式就是不错的选择,特别是当大多数参数都是可选的时候。
Builder比构建器更便于编写和阅读,比JavaBean更加安全。