標籤:java javabean builder constructor
靜態工廠和夠構造器有一個共同的局限性:遇到大量的參數時無法很好的擴充。
先說說構造器。
其實field不多時重疊構造器(telescoping constructor)是個不錯的方法,易於編寫也易於調用,這種方式在參數數量較少時也很常見。
但問題是參數很多(可能越來越多)時,比如(現在已經很難找到對多個參數進行重疊構造的代碼了,於是在這裡直接引用一下書中的代碼):
public class NutritionFacts {private final int servingSize; // (mL) requiredprivate final int servings; // (per container) requiredprivate final int calories; // optionalprivate final int fat; // (g) optionalprivate final int sodium; // (mg) optionalprivate final int carbohydrate; // (g) optionalpublic 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;}}
我想建立執行個體的時候,代碼會變成這個樣子:
public static void main(String[] args) {NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);}
雖然很難看,但這個可以有!
不過換個立場想一想,整個類裡獲得執行個體的方式就這麼一個破構造器讓你調用,你會是什麼感覺?
為了讓建立執行個體的過程變得更加清晰,於是我們有另一中選擇——JavaBean模式。
這個再熟悉不過了,如下:
public class NutritionFacts {// Parameters initialized to default values (if any)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() {}// Setterspublic void setServingSize(int val) {servingSize = val;}public void setServings(int val) {servings = val;}public void setCalories(int val) {calories = val;}public void setFat(int val) {fat = val;}public void setSodium(int val) {sodium = val;}public void setCarbohydrate(int val) {carbohydrate = val;}}
用起來雖然比只有一行的構造器多幾個步驟,但非常清晰:
public static void main(String[] args) {NutritionFacts cocaCola = new NutritionFacts();cocaCola.setServingSize(240);cocaCola.setServings(8);cocaCola.setCalories(100);cocaCola.setSodium(35);cocaCola.setCarbohydrate(27);}
現在我們想想JavaBean模式比起構造器重疊又有什麼缺點?
相比只通過一個構造器建立執行個體,JavaBean模式的執行個體的構造過程被分成了好幾個過程。
我們完全有可能在屬性不完整的情況下使用這個執行個體。
(按書中原文就是<A JavaBean may be in a inconsistent state partway through its construction.>)
當然,我們也可以做一些操作使其在未完成的情況下無法使用,但我不想因此讓一個類變得越來越複雜。
另外,我根本無法用JavaBean模式完全排除了將類設計成不可變(Immutable)的可能性。
此時,我們選擇使用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 parametersprivate final int servingSize;private final int servings;// Optional parameters - initialized to default valuesprivate 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也有缺點。
缺點1.建立執行個體前都要建立一個Builder執行個體。
缺點2.Builder模式編寫起來較為冗長。
但是,當構建一個執行個體需要很多步驟(或者很多讓人混淆的參數)的時候,Builder模式是個不錯的選擇。
本文出自 “Map.get(X)=new Object()” 部落格,請務必保留此出處http://runtime.blog.51cto.com/7711135/1433055