在面向對象程式設計過程中,通常通過構造器new的方式來擷取一個類的對象。這種方式比較适合對象屬性較少的情形。當對象的屬性過多時,這種方式就不太适合了。以一個食物商品為例,它擁有總脂肪量,膽固醇,鈉,蔗糖等20多個屬性,當我們生成該商品的對象時,有些屬性并不需要,于是我們會以重疊構造器的方式來編寫這個類。
public class Food01 {
private final int servingSize;
private final int serving;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Food01(int servingSize){
this(servingSize,0);
}
public Food01(int servingSize,int serving){
this(servingSize,serving,0);
}
public Food01(int servingSize,int serving,int calories){
this(servingSize,serving,calories,0);
}
public Food01(int servingSize,int serving,int calories,int fat){
this(servingSize,serving,calories,fat,0);
}
public Food01(int servingSize,int serving,int calories,int fat,int sodium){
this(servingSize,serving,calories,fat,sodium,0);
}
public Food01(int servingSize,int serving,int calories,int fat,int sodium,int carbohydrate){
this.servingSize = servingSize;
this.serving = serving;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
代碼中隻列舉了六個屬性,當屬性20多個時,以這種方式生成對象,将會導緻代碼龐大且難以編寫和閱讀。對于這種情況還有一種方式可以替代,就是通過javaBeans模式,通過set和get方法來設定對象的屬性,避免了大量的構造器。
Food food = new Food();
food.setServingSize(servingSize);
food.setServing(serving);
food.setcalories(calories);
javaBeans模式雖然解決了重疊構造器所遇到的問題,但是它有一個嚴重的缺點。它将所需屬性的對象的生成分成了好幾步完成,在food對象set屬性時可能會遭遇多線程問題,這需要程式員編寫額外代碼來保證線程安全。采用Builder模式就可以解決前面兩種方式遇到的問題。
Builder模式是在采用靜态内部類Builder,通過該靜态内部類調用類似setter的方法來設定屬性,在通過build方法生成所需的對象。具體代碼如下:
public class Food {
private final int servingSize;
private final int serving;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
private Food(Builder builder) {
serving = builder.serving;
servingSize = builder.servingSize;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public int getCalories() {
return calories;
}
static class Builder{
private final int servingSize;
private final int serving;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize,int serving) {
this.servingSize = servingSize;
this.serving = serving;
}
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 Food build() {
return new Food(this);
}
}
}
builder的每一個setter方法都傳回builder本身,使用者可以調用不同的setter方法來設定所需的屬性,最後将builder對象通過構造器的方式注入到Food對象,并将屬性複制到Food對象。采用builder模式,代碼就相對容易編寫,且易于閱讀。