0
2

More than 3 years have passed since last update.

【Effective Javaを読む】 第2章 項目2 『数多くのコンストラクタパラメータに直面した時にはビルダーを検討する』

Last updated at Posted at 2020-07-21

数多くのコンストラクタパラメータに直面した時にはビルダーを検討する

newする時にパラメータをたくさん渡してあげなきゃいけないようなクラスを作る時は
「ビルダー」を使うと可読性も安全性もあって良いよって話

サンプルコード

NutritionFactsという栄養成分を表すクラスが
一人前の分量、容器当たりの量、一人前のカロリー、etc たくさんのフィールドを持っている場合を例にして3つのパターンで考えてみる
・テレスコーピングコンストラクタ・パターン
 パラメータが多くなるとnewする時に引数に何を渡せば良いかわかりづらくなるし、可読性も下がってしまうのがデメリット

・JavaBeansパターン
 テレスコーピングコンストラクタ・パターンと違い可読性は上がるが、パラメータを設定している途中で不整合な状態ができてしまう

・ビルダーパターン
 テレスコーピングコンストラクタとJavaBeansのいいとこ取り!

例1
//テレスコーピングコンストラクタ・パターン
public class NutritionFacts{
    private final int servingSize;  //(mL)       必須
    private final int servings;     //(容器当たり)  必須
    private final int calories;     //           オプション
    private final int fat;          //(g)        オプション
    private final int sodium;       //(mg)       オプション
    private final int carbohydrate; //(g)        オプション

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

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

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

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

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

//newする時 見辛いね
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);

例2
//JavaBeansパターン
public class NutritionFacts{
    private int servingSize  = -1; //(mL)       必須
    private int servings     = -1; //(容器当たり)  必須
    private int calories     = 0;  //           
    private int fat          = 0;  //(g)        
    private int sodium       = 0;  //(mg)       
    private int carbohydrate = 0;  //(g)        

    public NutritionFacts(){ }

    //セッター
    public void setServingSize(int val)  { servingSize = val;}
    public void setServings(int val)     { servings = val;}
    public void setCalories(int val)     { calories = val;}
    public void setFat(int val)          { fat = val;}
    public void setSodium(int val)       { sodium = val;}
    public void setCarbohydrate(int val) { carbohydrate = val;}
}

//newする時 見易いけどsetしてる途中にアクセスされたらちょっと困る
NutritionFact cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

例3
//ビルダーパターン
public class NutritionFacts{
    private final int servingSize;  //(mL)       
    private final int servings;     //(容器当たり)
    private final int calories;     //           
    private final int fat;          //(g)        
    private final int sodium;       //(mg)       
    private final int carbohydrate; //(g)        

    public static class Builder{
        //必須パラメータ
        private final int servingSize;  //(mL)       
        private final int servings;     //(容器当たり)

        //オプションパラメータ
        private int calories     = 0;  //           
        private int fat          = 0;  //(g)        
        private int sodium       = 0;  //(mg)       
        private int carbohydrate = 0;  //(g)   

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

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

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

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

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

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

    private NutritionFacts(Builder builder){
         servingSize  = builder.servingSize;
         servings     = builder.servings;
         calories     = builder.calories;
         fat          = builder.fat;
         sodium       = builder.sodium;
         carbohydrate = builder.carbohydrate;
    }
}

//newする時 見易いし安全!
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
    calories(100).sodium(35).carbohydrate(27).build();

続く

【Effective Javaを読む】 第2章 項目3 『privateのコンストラクタかenum型でシングルトン特性を強制する』
https://qiita.com/Natsukii/items/ccd6893ce8add04d1777

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2