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個以上的參數。