天天看點

builder設計模式學習筆記

在面向對象程式設計過程中,通常通過構造器new的方式來擷取一個類的對象。這種方式比較适合對象屬性較少的情形。當對象的屬性過多時,這種方式就不太适合了。以一個食物商品為例,它擁有總脂肪量,膽固醇,鈉,蔗糖等20多個屬性,當我們生成該商品的對象時,有些屬性并不需要,于是我們會以重疊構造器的方式來編寫這個類。

public class Food01 {

    private final int servingSize;

    private final int serving;

    private int calories = 0;

    private int fat = 0;

    private int sodium = 0;

    private int carbohydrate = 0;

    public Food01(int servingSize){
        this(servingSize,0);
    }

    public Food01(int servingSize,int serving){
        this(servingSize,serving,0);
    }

    public Food01(int servingSize,int serving,int calories){
        this(servingSize,serving,calories,0);
    }

    public Food01(int servingSize,int serving,int calories,int fat){
        this(servingSize,serving,calories,fat,0);
    }

    public Food01(int servingSize,int serving,int calories,int fat,int sodium){
        this(servingSize,serving,calories,fat,sodium,0);
    }

    public Food01(int servingSize,int serving,int calories,int fat,int sodium,int carbohydrate){
        this.servingSize = servingSize;
        this.serving = serving;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}
           

代碼中隻列舉了六個屬性,當屬性20多個時,以這種方式生成對象,将會導緻代碼龐大且難以編寫和閱讀。對于這種情況還有一種方式可以替代,就是通過javaBeans模式,通過set和get方法來設定對象的屬性,避免了大量的構造器。

Food food = new Food();
food.setServingSize(servingSize);
food.setServing(serving);
food.setcalories(calories);
           

javaBeans模式雖然解決了重疊構造器所遇到的問題,但是它有一個嚴重的缺點。它将所需屬性的對象的生成分成了好幾步完成,在food對象set屬性時可能會遭遇多線程問題,這需要程式員編寫額外代碼來保證線程安全。采用Builder模式就可以解決前面兩種方式遇到的問題。

Builder模式是在采用靜态内部類Builder,通過該靜态内部類調用類似setter的方法來設定屬性,在通過build方法生成所需的對象。具體代碼如下:

public class Food {
    private final int servingSize;
    private final int serving;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    private Food(Builder builder) {
        serving = builder.serving;
        servingSize = builder.servingSize;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;

    }

    public int getCalories() {
        return calories;
    }

    static class Builder{
        private final int servingSize;
        private final int serving;

        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize,int serving) {
            this.servingSize = servingSize;
            this.serving = serving;
        }

        public Builder calories(int calories) {
            this.calories = calories;
            return this;
        }

        public Builder fat(int fat) {
            this.fat = fat;
            return this;
        }

        public Builder sodium(int sodium) {
            this.sodium = sodium;
            return this;
        }

        public Builder carbohydrate(int carbohydrate) {
            this.carbohydrate = carbohydrate;
            return this;
        }

        public Food build() {
            return new Food(this);
        }
    }


}
           

builder的每一個setter方法都傳回builder本身,使用者可以調用不同的setter方法來設定所需的屬性,最後将builder對象通過構造器的方式注入到Food對象,并将屬性複制到Food對象。采用builder模式,代碼就相對容易編寫,且易于閱讀。