オブジェクトの作成と破壊(2)


アイテムコンストラクション関数に多くのパラメータがある場合は、コンストラクタを考慮します。


静的ファクトリとジェネレータには同じ制限があります.これは,選択パラメータが多い場合には適切な対応が困難であるためである.
プログラマは通常、レイヤジェネレータモードを使用するのが好きです.
public class NutritionFacts {
    private final int servingSize; // 필수
    private final int servings; //필수
    private final int calories; //선택
    private final int fat; //선택
    private final int sodium // 선택
    private final int carbohydrate // 선택
    
    public NutrtionFacts(int servingSize, int servings){
    	this(servingSize, servigs, 0);
    }
    
    public NutrtionFacts(int sevingSize, int servings, int calories){
    	this(servingSize, servigs, caloreis, 0);
    }
    
    public NutrtionFacts(int sevingSize, int servings, int calories,int fat){
    	this(servingSize, servigs, caloreis, fat, 0);
    }
    public NutrtionFacts(int sevingSize, int servings, int calories,int fat, int sodium){
    	this(servingSize, servigs, caloreis, fat, sodium, 0);
    }
    
    public NutrtionFacts(int sevingSize, int servings, int calories,int fat,int sodium, int carbohydrate){
    	this.servingSize = servingSize;
        this.servings = sevings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}
クラスのインスタンスを作成するには、必要なパラメータをすべて含むコンストラクション関数の最短の1つを呼び出すだけです.
NutrtionFacts cocacola = new NutrtionFacts(240, 8, 100, 0, 35, 27);
通常、これらのジェネレータには、ユーザが望んでいないパラメータが含まれやすいが、これらのパラメータに値を指定しなければならない.
コードを読むと、各値の意味が混同されたり、パラメータが何個あるかを細かく数えたりする必要があります.クライアントがパラメータの順序を誤って変更しても、コンパイラは気づかず、最終的には実行時に予想外の動作をします.
今回は、2番目の選択パラメータが多い場合に使用できる代替案:JavaBeansモードを見てみましょう.
public class NutrtionFacts{
	private int servingSize = -1;
   private int servings = -1;
   private int calories = 0;
   private int fat = 0;
   private int sodium = 0;
   private int carbohydrate = 0; 
   
   public NutrtionFacts() {}
   // 세터 메서드들
   public void setServingsize(int val) { servingSize = val;}
   public void setServings(int val) { servings = val;}
   ... // 그 외의 메서드들
}
JavaBeansモードでは、オブジェクトを作成するには、複数のメソッドを呼び出し、オブジェクトを完全に作成する前にコンシステンシクラッシュ状態にする必要があります.
コンシステンシを破るオブジェクトを作成すると、エラーをインプラントしたコードとエラーにより、実行時に問題が発生したコードが物理的に遠く離れ、デバッグも困難になります.
このように、JavaBeansモードでは、スレッドの安定性を得るためにプログラマが追加の作業を行う必要があります.
幸いなことに、私たちは3つ目の代替案を持っています.
public class NutritionFacts {
  private final int servingSize;
  private final int servings;
  private final int calories;
  private final int fat;
  private final int sodium;
  private final int carbohydrate;

  //Builder가 static class인 이유는 부모(NutritionFacts) 클래스의 생성여부와 상관없이 독립적으로 사용하기 위함.
  public static class Builder {
    // 필수 매개변수
    private final int servingSize;
    private final int servings;

    // 선택 매개변수 - 기본값으로 초기화한다.
    private int calories      = 0;
    private int fat           = 0;
    private int sodium        = 0;
    private int carbohydrate  = 0;

    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;
  }

  public static void main(String[] args) {
    NutritionFacts cocaCola = new Builder(240, 8)
      .calories(100)
      .sodium(35)
      .carbohydrate(27)
            .build();
  }
}
NutrioninFactsクラスは不変クラスであり、すべてのパラメータのデフォルト値が1つの場所に集中しているため、Builderのメソッドはコンストラクタ自体に戻るため、連続的に呼び出すことができます.
main関数に示すように、クライアントはコードの使用と読み取りを容易にし、非栄養欠陥を生成します.
コンストラクタモードを使用する場合、重要な点は、誤ったパラメータが入力される可能性があるため、外部攻撃に対応するためにコンストラクタからパラメータをコピーし、オブジェクトを作成する前にこれらのオブジェクトフィールドをチェックする各メソッドで検証する必要があります.
次に、チェック後にエラーポイントが検出された場合、どのパラメータが無効なのかを詳細に説明し、IllegalArgumentException(不適切なパラメータを持つメソッド)を放出するメッセージを送信します.
コアのクリーンアップコンストラクタモードでは、コンストラクタオブジェクトに渡されるパラメータに基づいて異なるオブジェクトを作成する柔軟性があり、オブジェクトの作成時にオブジェクトを完了するため、可変クラスを作成することもできます.
ただし、コンストラクタモードでオブジェクトを作成する場合、コンストラクタオブジェクトの作成コストは大きくありませんが、パフォーマンスに問題が発生する可能性があるため、コンストラクタオブジェクトを先に作成する必要があるという欠点があります.
また,階層生成モードに比べてコードが冗長であり,パラメータが4個を超える場合にのみ価値がある.しかし,実際の作業では,パラメータは完全に4つを超えることができると考えられる.
その結果、コンストラクタモードは、レイヤ単位の生成モードに比べてクライアントの読み書きコードが非常に簡潔であり、JavaBeansモードよりも一貫性と不変性の面で安全である.