Telescoping Constructor Pattern (伸縮建構式)
首先這是個反模式(Anti-Pattern),在參數大於等於4個的情況下考慮使用 Builder Pattern 來替換。
伸縮建構式出現在具有多個參數建構式的類別中,如
public class Account { private String mName; private String mAge; private String mAddress; private String mTelephoneNumber; public Account(String name) { this(name, "unknow"); } public Account(String name, String age) { this(name, age, "unknow"); } public Account(String name, String age, String address) { this(name, age, address, "unknow"); } public Account(String name, String age, String address, String telephoneNumber) { mName = name; mAge = age; mAddress = address; mTelephoneNumber = telephoneNumber; } public void showInfo() { System.out.println("Name:" + mName + " Age:" + mAge + " Address:" + mAddress + " TelephoneNumber:" + mTelephoneNumber); } }
客戶端可以依照需要呼叫不同的建構式,如
Account foxx = new Account("Foxx"); foxx.showInfo(); Account peter = new Account("Peter", "23"); peter.showInfo();
Console
Name:Foxx Age:unknow Address:unknow TelephoneNumber:unknow Name:Peter Age:23 Address:unknow TelephoneNumber:unknow
該模式有幾個缺點,
1.客戶端難以了解不同參數以及不同建構式代表的意義。
2.客戶端有可能搞混參數順序而傳錯參數。
可以考慮使用 Builder Pattern 來替換伸縮建構式。
public class Account { private String mName; private String mAge; private String mAddress; private String mTelephoneNumber; public static class AccountBuilder { private String mName; private String mAge; private String mAddress; private String mTelephoneNumber; public AccountBuilder(String name) { mName = name; } public AccountBuilder age(String age) { mAge = age; return this; } public AccountBuilder address(String address) { mAddress = address; return this; } public AccountBuilder telephoneNumber(String telephoneNumber) { mTelephoneNumber = telephoneNumber; return this; } public Account build() { return new Account(this); } } private Account(AccountBuilder builder) { mName = builder.mName; mAge = builder.mAge; mAddress = builder.mAddress; mTelephoneNumber = builder.mTelephoneNumber; } public void showInfo() { System.out.println("Name:" + mName + " Age:" + mAge + " Address:" + mAddress + " TelephoneNumber:" + mTelephoneNumber); } }
其中 AccountBuilder 即是 Builder Pattern 的主角,使用其建構式(第14行)來規定必須要傳入的參數。
接著建立其他方法(age() , address(), telephoneNumber())來設定屬性,這些方法因為具有明確的名稱可以讓客戶端容易了解方法的意圖。
最後藉由 build 方法回傳 Account 實體。
客戶端呼叫
Account foxx = new Account.AccountBuilder("Foxx").age("unknow").address("unknow").telephoneNumber("unknow").build(); foxx.showInfo();
Console
Name:Foxx Age:unknow Address:unknow TelephoneNumber:unknow
Note
為了確保各個屬性的正確,可以在build方法加入檢查機制。
public static AccountBuilder{ ... public Account build() { if(mAge == null){ throw new IllegalArgumentException(); } return new Account(this); } ... }
該檢查機制會在客戶端沒有呼叫age()方法而產生Account實體丟出Exception。
Account peter = new Account.AccountBuilder("Peter").build();
Console
Exception in thread "main" java.lang.IllegalArgumentException
缺點:
1.必須先建立 builder 角色,效能可能會受影響。
2.Builder Pattern 的內容比 telescoping constructor 還長,因此適用於4個以上的參數。