當類別擁有多個可選參數時,傳統上有三種處理方式:重疊建構子、JavaBeans 模式、Builder 模式。前兩者皆有明顯缺陷。
提供多個建構子,參數遞增。缺點:參數多時難以閱讀,且參數順序顛倒編譯器不報錯,執行期才出錯。
public class NutritionFacts1 {
private int a1, a2, a3, a4;
public NutritionFacts1(int a1, int a2) { this(a1, a2, 0); }
public NutritionFacts1(int a1, int a2, int a3) { this(a1, a2, a3, 0); }
public NutritionFacts1(int a1, int a2, int a3, int a4) { ... }
}
無參建構子 + setter 方法。缺點:物件構建過程分散在多個呼叫中,可能處於不一致狀態,需額外努力保證執行緒安全。
public class NutritionFacts2 {
private int a1 = -1, a2 = -1, a3, a4;
public NutritionFacts2() { }
public void setA1(int a1) { this.a1 = a1; }
// ... 其他 setter
}
結合了建構子的安全性與 JavaBeans 的可讀性:
Builder 物件。this 支援鏈式調用)。build() 產生不可變物件。
public class NutritionFacts3 {
private final int a1, a2, a3, a4;
public static class Builder {
private final int a1, a2;
private int a3 = 0, a4 = 0;
public Builder(int a1, int a2) { this.a1 = a1; this.a2 = a2; }
public Builder setA3(int a3) { this.a3 = a3; return this; }
public Builder setA4(int a4) { this.a4 = a4; return this; }
public NutritionFacts3 build() { return new NutritionFacts3(this); }
}
private NutritionFacts3(Builder b) { a1 = b.a1; a2 = b.a2; a3 = b.a3; a4 = b.a4; }
}
用法:
NutritionFacts3 nf = new NutritionFacts3.Builder(1, 2).setA3(3).setA4(4).build();
Builder 模式適用於參數較多、尤其是可選參數眾多的場景,能確保物件創建的原子性與不可變性。