1. 程式人生 > >二、當構造方法參數過多時使用build模式

二、當構造方法參數過多時使用build模式

構造 使用 靜態工廠 ngs oid 模式 uil etag 構建

  靜態工廠方法和構造方法都有同一個缺陷:當可選參數過多時,它們都沒有辦法很好的進行擴展。所以,當參數過多時,一般采用的方法有:可伸縮構造方法模式(the telescoping constructor pattern)、javaBeans模式和Builder模式。

1、telescoping constructor模式

  (1)如何使用

    在telescoping constructor模式中,首先提供一個必需參數的構造方法,然後再加一個可選參數形成第二個構造方法,接著再加一個可選參數形成第三個構造方法,等等,直到構造方法中包含所有的可選參數。例如:

 1 public class
Person { 2 private String name; // 必需 3 private String nickname; // 必需 4 private int age; // 可選 5 private String phone; // 可選 6 7 public Person(String name, String nickname) { 8 this(name, nickname, 0); 9 } 10 11 public Person(String name, String nickname, int
age) { 12 this(name, nickname, age, null); 13 } 14 15 public Person(String name, String nickname, int age, String phone) { 16 this.name = name; 17 this.nickname = nickname; 18 this.age = age; 19 this.phone = phone; 20 } 21 }

  實例化方法:Person p = new Person("張三", "小小");

  (2)缺點

    • 當對象實例化時,你可能會需要對你不想設置的參數傳值
    • 當參數很多時,客戶端代碼很難編寫,也很難進行閱讀

2、JavaBeans模式

  (1)如何使用

    在JavaBeans模式中,先調用一個無參構造方法創建對象,然後調用類中的setter方法設置參數。例如:

 1 public class Person {
 2      private String name;          // 必需
 3      private String nickname;    // 必需
 4      private int age;                  // 可選
 5      private String phone;         // 可選
 6 
 7      public Person() {}
 8 
 9      public void setName(String name) {
10        this.name = name;
11      } 
12 
13      public void setNickname(String nickname) {
14         this.nickname = nickname;
15      }
16 
17      public void setAge(int age) {
18         this.age = age;
19      }
20 
21      public void setPhone(String phone) {
22        this.phone = phone;
23      }
24 }

  實例化方法: Person p = new Person();

         p.setName("張三");

         p.setNickname("小小");

  (2)缺點

    由於構造方法在多次調用中被分割,所以JavaBeans模式是線程不安全的,在多線程模式下,對象的值可能會發生變化。

3、Builder模式

  (1)如何使用

    builder模式結合了telescoping constructor模式的安全性和JavaBeans模式的可讀性。客戶端不直接調用所需對象,而是使用所有必須參數的構造方法(或靜態工廠方法)來獲取一個bulider對象;然後客戶端調用builder對象的和setter相似的方法來設置每個可選參數;最後,客戶端調用一個無參的builder方法來生成一個對象。

 1 public static class Pizza {
 2     public enum Topping {HAM, MUSHROOM, ONION}
 3     final Set<Topping> toppings;
 4 
 5     abstract static class Builder<T extends Builder<T>> {
 6         EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
 7         public T addTopping(Topping topping) {
 8             toppings.add(topping);
 9             return self();
10         }
11         abstract Pizza build();
12 
13         protected abstract T self();
14     }
15 
16     Pizza(Builder<?> builder) {
17         toppings = builder.toppings.clone();
18     }
19 }
20 
21 public class MyPizza extends Pizza {
22     public enum Size{SMALL, MEDIUM, LARGE}
23     private final Size size;
24 
25     public static class Builder extends Pizza.Builder<Builder> {
26         private final Size size;
27 
28         public Builder(Size size) {
29             this.size = size;
30         }
31 
32         @Override
33         public MyPizza build() {
34             return new MyPizza(this);
35         }    
36 
37         @Override
38         protected Builder self() {
39             return this;
40         }
41     }
42 
43     private MyPizza(Builder builder) {
44         super(builder);
45         size = builder.size;
46     }
47 }

  實例化方法:MyPizza pizza = new MyPizza.Builder(SMALL).addTopping(SAUAGE).build();

  (2) 缺點

    為了創建對象,必須先創建對象的builder,所以在關鍵的時候,性能會有稍許影響,而且builder模式的構建比較麻煩。

4、總結

  當設計類的構造方法或靜態工廠的參數超過幾個時,Builder模式是一個不錯的選擇,特別是如果許多參數是可選的或相同類型的。

二、當構造方法參數過多時使用build模式