아이템2. 생성자에 매개변수가 많다면 빌더를 고려하라

정적 팩터리와 생성자는 선택적 매개변수가 많을 때 적절히 대응하기 어렵다!

매개변수가 많을 때 어떻게 할까?

점층적 생성자 패턴을 많이 사용하나

매개변수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.


public class NutritionFacts1 {
    private final int servingSize;  // (ml, 1회 제공량)       필수
    private final int servings;  // (회, 총 n회 제공량)       필수
    private final int calories;  // (1회 제공량당)       선택
    private final int fat;  // (g/1회 제공량)       선택
    private final int sodium;  // (mg/1회 제공량)       선택
    private final int carbonhydrate;  // (g/1회 제공량)       선택

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

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

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

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

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


두번째 대안은 자바빈즈 패턴!!

매개변수가 없는 생성자로 객체를 만든 후, 세터 메서드들을 호출해 원하는 매개변수의 값을 설정하는 방식


// 자바빈즈 패턴 - 일관성이 깨지고 불변으로 만들 수 없다.
public class NutritionFacts2 {
    // 매개변수들을 (기본값이 있다면) 기본값으로 초기화된다.
    private int servingSize = -1; // 필수: 기본값 없음
    private int servings = -1; // 필수: 기본값 없음
    private int calories = 0;
    private int fat = 0;
    private int sodium = 0;
    private int carbonhydrate = 0;

    public NutritionFacts2() {
    }

    // setters
    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 setCarbonhydrate(int carbonhydrate) {
        this.carbonhydrate = carbonhydrate;
    }

    public static void main(String[] args) {
        NutritionFacts2 cocaCola = new NutritionFacts2();
        cocaCola.setServingSize(240);
        cocaCola.setServings(8);
        cocaCola.setCalories(100);
        cocaCola.setSodium(35);
        cocaCola.setCarbonhydrate(27);
    }
}


신에게는 아직 세번째 대안이 있사옵나이다.

바로 바로 바로 점층적 생성자 패턴의 안전써엉!!과 자바빈즈 패턴의 가독성까지!!! 겸비한 인재 빌더 패턴이시다.

클라이언트는 필요한 객체를 직접 만드는 대신, 필수 매개변수만으로 생성자(혹은 정적 팩터리)를 호출해 빌더 객체를 얻는다.


public class NutritionFacts3 {
    private final int servingSize;  // (ml, 1회 제공량)       필수
    private final int servings;  // (회, 총 n회 제공량)       필수
    private final int calories;  // (1회 제공량당)       선택
    private final int fat;  // (g/1회 제공량)       선택
    private final int sodium;  // (mg/1회 제공량)       선택
    private final int carbonhydrate;  // (g/1회 제공량)       선택

    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 carbonhydrate = 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 carbonhydrate(int val) {
            carbonhydrate = val;
            return this;
        }

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

    public NutritionFacts3(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbonhydrate = builder.carbonhydrate;
    }

    public static void main(String[] args) {
        NutritionFacts3 cocaCola = new NutritionFacts3.Builder(240, 8)
                .calories(100).sodium(35).carbonhydrate(27).build();

    }
}

### 빌더패턴은 (파이썬과 스칼라에 있는) 명명된 선택적 매개변수를 베낀.. 흉내낸 것이다.
  • 빌더 패턴은 계층적으로 설계된 클래스와 함께 쓰기에 좋다.

계층적으로 설계된 클래스와 잘 어울리는 빌더 패턴 
코드 작성 예정 

핵심정리

생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다.
매개변수 중 다수가 필수가 아니거나 같은 타입이면 특히 더 그렇다. 빌더는 점층적 생성자보다 클라이언트 코드를 읽고
쓰기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.

좋은 웹페이지 즐겨찾기