在設計模式中對Builder模式的定義是用於構建複雜物件的一種模式,所構建的對象往往需要多步初始化或賦值才能完成。那麼,在實際的開發過程中,我們哪些地方適合用到Builder模式呢?其中使用Builder模式來替代多參數建構函式是一個比較好的實踐法則。
我們常常會面臨編寫一個這樣的實作類別(假設類名叫DoDoContact),這個類擁有多個建構函式,
DoDoContact(String name);
DoDoContact(String name, int age);
DoDoContact(String name, int age, String address);
DoDoContact(String name, int age, String address, int cardID);
這樣一系列的建構函式主要目的就是為了提供更多的客戶調用選擇,以處理不同的構造請求。這種方法很常見,也很有效力,但是它的缺點也很多。類的作者不得不書寫多種參數組合的建構函式,而且其中還需要設定預設參數值,這是一個需要細心而又枯燥的工作。其次,這樣的建構函式靈活性也不高,而且在調用時你不得不提供一些沒有意義的參數值,例如,DoDoContact("Ace", -1, "SH"),顯然年齡為負數沒有意義,但是你又不的不這樣做,得以符合Java的規範。如果這樣的代碼發布後,後面的維護者就會很頭痛,因為他根本不知道這個-1是什麼含義。對於這樣的情況,就非常適合使用Builder模式。Builder模式的要點就是通過一個代理來完成對象的構建過程。這個代理職責就是完成構建的各個步驟,同時它也是易擴充的。下面是改寫自Effective Java裡面的一段代碼:
public class DoDoContact { private final int age; private final int safeID; private final String name; private final String address; public int getAge() { return age; } public int getSafeID() { return safeID; } public String getName() { return name; } public String getAddress() { return address; } public static class Builder { private int age = 0; private int safeID = 0; private String name = null; private String address = null;
// 構建的步驟 public Builder(String name) { this.name = name; } public Builder age(int val) { age = val; return this; } public Builder safeID(int val) { safeID = val; return this; } public Builder address(String val) { address = val; return this; } public DoDoContact build() { // 構建,返回一個新對象 return new DoDoContact(this); } } private DoDoContact(Builder b) { age = b.age; safeID = b.safeID; name = b.name; address = b.address; }}
最終,客戶程式可以很靈活的去構建這個對象。
DoDoContact ddc = new DoDoContact.Builder("Ace").age(10) .address("beijing").build();System.out.println("name=" + ddc.getName() + "age =" + ddc.getAge() + "address" + ddc.getAddress());