Effective Item 2 - 遇到多個構造器參數時考慮使用Builder

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.