昨天說到了constructor參數太多的一些缺點,以及JavaBeans pattern這個替代方案,還有使用JavaBeans pattern會出現的問題,今天終於要介紹另外一個替代方案-builder pattern。
builder pattern的實作方式,是在class裡面建一個inner class,然後透過這個inner class給使用者設定值,最後在呼叫build(),讓constructor根據builder的值去實體化類別。
public class NutritionFacts {
private final int calories; //required
private final int weight; //required
private final int carbohydrate; //optional
private final int sodium; //optional
private final int fat; //optional
private final int sugar; //optional
public static class Builder {
private final int calories; //required
private final int weight; //required
private int carbohydrate; //optional
private int sodium; //optional
private int fat; //optional
private int sugar; //optional
public Builder(int calories, int weight) {
this.calories = calories;
this.weight = weight;
}
public Builder carbohydrate(int val) {
carbohydrate = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder sugar(int val) {
sugar = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
calories = builder.calories;
weight = builder.weight;
carbohydrate = builder.carbohydrate;
sodium = builder.sodium;
fat = builder.fat;
sugar = builder.sugar;
}
}
builder pattern最大的優點是可以防止使用者隨意變動變數的值,而且在build()產生object的時候,可以做型別檢查,避免跟JavaBeans pattern一樣,等到runtime的時候才發現錯誤。
class main {
public static void main(String[] args) {
NutritionFacts hamburger = new NutritionFacts.Builder(33,33)
.carbohydrate(50)
.sodium(5)
.fat(30)
.build();
System.out.println(hamburger);
}
}
總結來說,如果類別的變數很多(也許超過四個),而且很多變數都是optional,那麼就可以考慮使用builder pattern,但如果變數不多,使用constructor就足夠,畢竟builder pattern必須撰寫比較複雜的程式碼,對後續維護也是一個負擔。