靜態工廠和構造器有一個共同的局限性:它們都不能很好地擴展到大量的可選參數。如果一個構造器的參數有10,11,12,...或更多時。一長串類型相同的參數會導致一些微妙的錯誤,如果不小心顛倒了其中兩個參數的順序,編譯器也不會出錯,但是程序在運行時會出現錯誤的行為。
遇到許多構造參數的時候,還有第二種代替辦法,及JavaBean模式,在這種模式下調用一個無慘構造器來創建對象,調用setter方法來設置每個必要的參數,以及每個相關的可選參數。
Effective Java一書中提到:JavaBean模式自身有著很嚴重的缺點,因為構造過程分到了幾個調用中,在構造過程中JavaBean可能處于不一致的狀態。類無法僅僅通過檢驗構造器參數的有效性來保證一致性。視圖使用處于不一致的對象,將會導致失敗。這種失敗與包含錯誤的代碼大相徑庭。與此相關的另一點不足在于,JavaBean模式阻止了把類做成不可變的可能,這就需要程序員付出額外的努力來確保它的線程是安全的。
附注:個人在使用中,還沒有發現這個問題,如有了解的大神,還請不吝賜教。
最佳替代方法Builder模式,既能保證像重疊構造器模式那樣的安全性,也能保證像JavaBean模式那么好的可讀性。Builder模式,不直接生成想要的對象,而是讓客戶端在builder對象上調用類似于setter的方法,來深圳每個相關的可選參數。最后,客戶端調用無參的builder方法生成不可變的對象。這個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;
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 val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; 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;
}
public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
}
}
此處Builder類作為一個靜態內部類。我們最終要獲得的是NutritionFacts對象,從他的構造函數可以看出,是通過builder對象來對他的屬性進行初始化的。而builder對象的屬性是通過多個setter方法設置的。