场景
当前有一个实体类用于表示食品外包装的营养元素(份量、份数、卡路里、脂肪、钠、碳水化合物等…)
/**
* 该类表示一个食品包装 营养成分元素类
*/
public class NutritionFacts {
private int servingSize; // 份量 (必须)
private int servings; // 份数 (必须)
private int calories; // 卡路里 (可选)
private int fat; // 脂肪 (可选)
private int sodium; // 钠 (可选)
private int carbohydrate; // 碳水化合物 (可选)
}
这些属性有些是必要的有些是不必要的,如何应对需要不同属性组合在一起的情况?
一、构造器方式
1.使用全参构造器
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;
}
2.使用重叠构造器
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;
}
不管是全参构造器还是重叠构造器,当参数越来越多时,代码的可读性以及代码编写的复杂性将越来越大,使工作难度增加。
二、JavaBeans方式
在这种方式下,我们先调用一个无参构造器来创建一个对象,之后再调用set方法来设置必要属性与那些我们关注的属性。
public static void main(String[] args) {
NutritionFacts nutritionFacts = new NutritionFacts();
nutritionFacts.setServingSize(240);
nutritionFacts.setCalories(200);
nutritionFacts.setFat(6);
nutritionFacts.setSodium(1200);
}
但同时这种方式也有很大的缺点。因为一个对象的构造过程被分到了多个调用中,在构造过程中JavaBean可能处于不一致的状态。同时JavaBeans模式使得类变成不可变的可能性不复存在(因为存在set方法),这就需要我们付出更多的经历来确保它的线程安全问题。
三、构建器方式(建造者模式的一种)
这种方式是让客户端利用所有必要的参数调用构造器,得到一个Builder对象。然后客户端在builder对象上调用类似于setter的方法,设置每个相关的可选参数。最后,客户端调用无参的build方法来生成通常是不可变的对象。
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 sodium(int sodium) {
this.sodium = sodium;
return this;
}
public Builder carbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
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;
}
builder的设值方法会返回builder本身,这样是为了方便把调用链接起来,得到一个流式API。
public static void main(String[] args) {
NutritionFacts nutritionFacts =
new NutritionFacts.Builder(200,240).calories(1).fat(2).build();
}