我們在平常類的構建過程中,可能會面臨很多問題,可擴張性、安全性等等。想象一下,這樣一個場景,我們現在要創建一個類,其中有6個屬性,其中又有4個屬性的值是不太確定的(可能某個對象就不需要其中的某個值),這時我們怎么創建這個類呢?以下是幾種方法:
使用普通構造器
1 public class Test { 2 private int servingSize; 3 private int servings; 4 private int calories; 5 private int fat; 6 private int sodium; 7 private int carbohydrate; 8 9 public Test(int servingSize, int servings) { 10 this.servingSize = servingSize; 11 this.servings = servings; 12 this.calories = 0; 13 } 14 15 public Test(int servingSize, int servings, int calories) { 16 this.servingSize = servingSize; 17 this.servings = servings; 18 this.calories = calories; 19 this.fat = 0; 20 } 21 22 public Test(int servingSize, int servings, int calories, int fat) { 23 this.servingSize = servingSize; 24 this.servings = servings; 25 this.calories = calories; 26 this.fat = fat; 27 this.sodium = 0; 28 } 29 30 public Test(int servingSize, int servings, int calories, int fat, int sodium) { 31 this.servingSize = servingSize; 32 this.servings = servings; 33 this.calories = calories; 34 this.fat = fat; 35 this.sodium = sodium; 36 this.carbohydrate = 0; 37 } 38 39 public Test(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) { 40 this.servingSize = servingSize; 41 this.servings = servings; 42 this.calories = calories; 43 this.fat = fat; 44 this.sodium = sodium; 45 this.carbohydrate = carbohydrate; 46 } 47 48 }
我們完成該類構建后,接下來就是調用的過程:
1 public static void main(String[] args) { 2 Test test = new Test(1,2,3,0,5,6); 3 }
如上所示,在實例化對象時,我們需要傳入相應的值,這時發現:
- 第四個參數不是我們需要的,但是還不得不給他傳遞一個值
- 我們在傳值時,很容易出錯,某兩個參數值互換了位置,這在工作時是不好發現的,但是程序會報錯
所以上面的方式在涉及到參數比較多,而且參數值不太確定是否需要時,這種方法會給我們的編碼以及后期維護帶來很大的困擾,我們再改進一下。
JavaBeans模式
1 public class Test { 2 private int servingSize; 3 private int servings; 4 private int calories; 5 private int fat; 6 private int sodium; 7 private int carbohydrate; 8 9 public Test() { 10 11 } 12 13 public void setServingSize(int servingSize) { 14 this.servingSize = servingSize; 15 } 16 17 public void setServings(int servings) { 18 this.servings = servings; 19 } 20 21 public void setCalories(int calories) { 22 this.calories = calories; 23 } 24 25 public void setFat(int fat) { 26 this.fat = fat; 27 } 28 29 public void setSodium(int sodium) { 30 this.sodium = sodium; 31 } 32 33 public void setCarbohydrate(int carbohydrate) { 34 this.carbohydrate = carbohydrate; 35 } 36 37 38 }
如上,我們先創建一個無參構造方法(可以不寫出來,會默認創建),接下來就是利用setter方法給屬性賦值
1 public static void main(String[] args) { 2 Test test = new Test(); 3 test.setServingSize(1); 4 test.setCalories(2); 5 test.setCalories(3); 6 test.setSodium(5); 7 test.setCarbohydrate(6); 8 }
如上,我們需要的對象不需要fat屬性,我們就不用給其賦值,這中方法有幾個好處:
- 客戶端調用簡單,也就是實例化對象的過程十分簡單,並且不會出現把值傳遞出錯的風險
- 別人能夠很好的使用且理解簡單
但是我們知道,javaBeans有個缺點:
- 線程不安全,因為對象的創建分在了好幾步的過程中,不能保證對象狀態的一致性
我們可以確保線程的安全,這就需要我們額外的精力(我們可以在對象構造完成,並且不允許在凍結之前使用時,手動凍結,實際中很少使用,編譯器無法確定我們是否調用的freeze方法
)。因此這種方法也不夠理想,還有什么繼續改進的地方嗎?
構建器(建造者模式的一種形式)
1 public class Test { 2 private int servingSize; 3 private int servings; 4 private int calories; 5 private int fat; 6 private int sodium; 7 private int carbohydrate; 8 9 public static class Builder { 10 private int servingSize; 11 private int servings; 12 private int calories; 13 private int fat; 14 private int sodium; 15 private int carbohydrate; 16 17 public Builder (int servingSize, int servings) { 18 this.servingSize = servingSize; 19 this.servings = servings; 20 } 21 22 public Builder calories(int calories) { 23 calories = calories; 24 return this; 25 } 26 27 public Builder fat(int fat) { 28 fat = fat; 29 return this; 30 } 31 32 public Builder sodium(int sodium) { 33 sodium = sodium; 34 return this; 35 } 36 37 public Builder carbohydrate(int carbohydrate) { 38 carbohydrate = carbohydrate; 39 return this; 40 } 41 42 public Test builder () { 43 return new Test(this); 44 } 45 } 46 47 private Test(Builder builder) { 48 servingSize = builder.servingSize; 49 servings = builder.servings; 50 calories = builder.calories; 51 fat = builder.fat; 52 sodium = builder.sodium; 53 carbohydrate = builder.carbohydrate; 54 } 55 }
調用方式:
1 public static void main(String[] args) { 2 Test test = new Builder(1,2).calories(3).fat(4).sodium(5).carbohydrate(6).builder(); 3}
這樣就保證了對象在不變的情況下,簡單明了地實現了對象實例化(至於代碼中的內部類,我們以后細說)。