Java物件建立模式

blue星空發表於2020-07-18

 

    建立Java物件時,對於可為空的屬性,建立物件的時候有3種模式:重疊構造器模式、JavaBeans模式、Builder模式(推薦)、Stream模式(推薦)。

 


                                                            重疊構造器模式

 
     該模式使用多個構造器建立Java物件。
     該寫法符合Java的標準慣例,但是隨著引數的越來越多,程式碼變得越來越難寫。而且該方式靈活性低,可讀性較差,客戶端想要知道哪些值的具體含義,還需要仔細數引數,而且還容易寫錯引數的位置。 
package effectiveJava.builder;

public class NutritionFactsMultiContr {
    //食物尺寸
    private int servingSize;
    //食物數量
    private int servings;
    //熱量(卡路里)
    private int calories;
    //脂肪含量
    private int fat;
    //食用鹽(鈉)含量
    private int sodium;
    //糖類含量
    private int carbohydrate;

    public NutritionFactsMultiContr(int servingSize, int servings) {
        this(servingSize,servings,0);
    }

    public NutritionFactsMultiContr(int servingSize, int servings, int calories) {
        this(servingSize,servings,calories,0);
    }

    public NutritionFactsMultiContr(int servingSize, int servings, int calories, int fat) {
        this(servingSize,servings,calories,fat,0);
    }

    public NutritionFactsMultiContr(int servingSize, int servings, int calories, int fat, int sodium) {
        this(servingSize,servings,calories,fat,sodium,0);
    }

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

    public static void main(String[] args) {
        NutritionFactsMultiContr nutritionFacts = new NutritionFactsMultiContr(1,2,3,4,5,6);
    }

}

  


                                                    JavaBeans模式

     
      該模式通過呼叫一個無參構造器來建立物件,並使用setter方法來設定引數值。
      該模式彌補了重疊構造器模式的不足,而且創造例項很容易,程式碼的可讀性也高。但是JavaBeans模式將構造過程分到幾個步驟中,在構造過程中JavaBean可能處於不一致的狀態,導致一些未知的錯誤。同時,JavaBeans模式阻止了把類做成不可變的可能。
package effectiveJava.builder;
//營養成分
public class NutritionFactsSetter {

    //食物尺寸
    private int servingSize;
    //食物數量
    private int servings;
    //熱量(卡路里)
    private int calories;
    //脂肪含量
    private int fat;
    //食用鹽(鈉)含量
    private int sodium;
    //糖類含量
    private int carbohydrate;


    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }


    public void setServings(int servings) {
        this.servings = servings;
    }


    public void setCalories(int calories) {
        this.calories = calories;
    }


    public void setFat(int fat) {
        this.fat = fat;
    }


    public void setSodium(int sodium) {
        this.sodium = sodium;
    }


    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }


    public static void main(String[] args) {
        NutritionFactsSetter nutritionFacts = new NutritionFactsSetter();
        nutritionFacts.setCalories(1);
        nutritionFacts.setCarbohydrate(2);
    }
}

  


                                                                       Builder模式

 
    該模式不直接生成想要的物件,而是先建立一個builder物件,再在builder上呼叫類似setter的方法設定引數值,最後呼叫無參的build方法來生成所需要的物件。(注意:Builder模式下,想要建立的物件的構造器是私有的,這樣建立出來的物件是不可變的
     該模式既能像重疊構造器模式那樣的安全性,也能保證像JavaBeans模式那樣的可讀性,同時實現了物件的不可變性。但是Builder模式為了建立物件,必須先建立它的構建器,導致程式碼有點冗餘。
     Builder模式模擬了具名的可選引數。
package effectiveJava.builder;
//營養成分
public class NutritionFacts {


    //食物尺寸
    private int servingSize;
    //食物數量
    private int servings;
    //熱量(卡路里)
    private int calories;
    //脂肪含量
    private int fat;
    //食用鹽(鈉)含量
    private int sodium;
    //糖類含量
    private int carbohydrate;

    /**
     * NutritionFacts是不可變的,不對外提供構造器
     * @param builder
     */
    private NutritionFacts(Builder builder) {
        this.servingSize = builder.servingSize;
        this.servings = builder.servings;
        this.calories = builder.calories;
        this.fat = builder.fat;
        this.sodium = builder.sodium;
        this.carbohydrate = builder.carbohydrate;
    }

    public static class Builder {
        private int servingSize;
        private int servings;
        private int calories;
        private int fat;
        private int sodium;
        private int carbohydrate;


        //必填欄位
        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        //可選欄位
        public Builder calories(int val){
            this.calories = val;
            return this;
        }

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

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

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

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

    public static void main(String[] args) {
        NutritionFacts facts = new NutritionFacts.Builder(1, 2).calories(3).fat(4).build();
    }
}

  


                                                                    Stream模式

   
    Java8中引入了一種新特性Stream,這讓編碼變得更加簡單易讀(其實,該思想在以前的JDK版本中也有使用,例如:StringBuilder、StringBuffer)。在物件的建立過程中,我們也可以使用Stream思想。
    Stream模式就是將setter方法的返回值變為物件本身,這樣就可以連續呼叫setter方法。
package effectiveJava.builder;

public class NutritionFactsStream {
    //食物尺寸
    private int servingSize;
    //食物數量
    private int servings;
    //熱量(卡路里)
    private int calories;
    //脂肪含量
    private int fat;
    //食用鹽(鈉)含量
    private int sodium;
    //糖類含量
    private int carbohydrate;

    public NutritionFactsStream() {
    }

    public int getServingSize() {
        return servingSize;
    }

    public NutritionFactsStream setServingSize(int servingSize) {
        this.servingSize = servingSize;
        return this;
    }

    public int getServings() {
        return servings;
    }

    public NutritionFactsStream setServings(int servings) {
        this.servings = servings;
        return this;
    }

    public int getCalories() {
        return calories;
    }

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

    public int getFat() {
        return fat;
    }

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

    public int getSodium() {
        return sodium;
    }

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

    public int getCarbohydrate() {
        return carbohydrate;
    }

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

    public static void main(String[] args) {
        NutritionFactsStream nutritionFacts = new NutritionFactsStream().setServings(1).setServings(2);
    }
}

 

      此外,建立物件的模式還有很多,比如:工廠模式、單例模式等,不是本文討論的重點,有興趣的可以自己研究一下。

 

參考資料:

  • Joshua Bloch 《Effective Java》
 

相關文章