您的位置:首页 > 产品设计 > UI/UE

使用Builder模式代替来创建实例

2015-04-06 15:09 288 查看
引入:

考虑有这样一个类的设计,它用来表示包装食品外面的营养标签,包含以下内容:

每罐的含量(servingSize)

营养品的种类(servings)

卡路里(calories)

脂肪含量(fat)

钠含量(sodium)

糖含量(carbohydrate)。

其中前两个是必须的,后面几项是可选的。

对于这样的类,应该用哪种构造方法或者静态方法来编写呢?一种常用的方法是采用重叠构造器(telescoping constructor)。例如:

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;
}


这种方法可行,但是当有许多参数时,客户端代码会很难编写,并且较难阅读。如果读者想明白这些值是什么意思,需要仔细的数着参数来探个究竟。一长串类型相似的参数会导致一些微妙的错误,如果客户端不小心颠倒了其中两个参数的顺序,编译器不会报错,但在程序运行时会出现错误的行为。

方案二

调用一个无参的构造方法来创建对象,然后调用setter方法来设置每个必要的参数,以及每个必要的参数。

public class NutritionFacts {
private int servingSize = -1;
private int servings = -1;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;

public NutritionFacts() {}

//setters
public void setServingSize(int val) {servingSize = val;}
public void setServings(int val){servings = val;}
public void setCalories(int val){calories = val;}
pubic void setSodium(int val) {sodium = val;}
public void setCarbohydrate(int val){carbohydrate = val;}
}

这种模式弥补了重叠构造器模式的不足。就是创建实例容易,这样产生的代码也容易阅读。

NutritionFacts cocaCola = new NutritionFacts();

cocaCola.setServingSize(240);

cocaCola.setServings(8);

cocaCola.setCalories(100);

cocaCola.setSodium(35);

cocaCola.setcarbohydrate(27);

优缺点:

因为构造过程被分到了几个调用中,类的对象可能处于不一致的状态。类无法通过检验构造器参数的有效性来保证一致性。试图使用处于不一致状态的对象,将会导致失败,而且,这种模式阻止了把类做成不可变的可能。

方案三(Builder模式)

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;

pubic static class Builder{
private final int servingSize;
private final int servings;

private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;

pubic Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
this.calories = val;
return this;
}
public Builder fat(int val) {
this.fat = val;
return this;
}
public Builder carbohydrate(int val) {
this.carbohydrate = val;
return this;
}
public Builder sodium(int val) {
this.sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
//私有Constructor表明创建NutritionFacts对象时,只能通过Builder对象的build()方法。
private NutritionFacts(Builder builder) {
serviceSize = builder.serviceSize;
servings = builder.servings;

calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
//test case.
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240,8).calories(100).sodium(35)
.carbohydrate(27).build();
}
}

Builder模式可以有多个可变参数,使用单独的方法来设置每个参数。简言之,如果类的Constructor或静态工厂方法中有多个参数,就可以考虑使用Builder模式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: