[이펙티브 자바] item2. 생성자에 매개변수가 많다면 빌더를 고려하라

ideal dev·2023년 7월 13일
0

이펙티브 자바

목록 보기
2/3

생성자에 매개변수가 많은 경우엔

public class NutritionFacts {
    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 carbohydrate; // (g/1회 제공량)       선택

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

    public NutritionFacts(int servingSize, int servings,
                          int calories) {
        this.sevingSize = 	servingSize;
  		this.servings	=	servings;
  		this.calories	=	calories;
    }

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

    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium) {
        this.sevingSize = 	servingSize;
  		this.servings	=	servings;
  		this.calories	=	calories;
  		this.fat 		=	fat;
  		this.sodium		=	sodium;
    }
    public NutritionFacts(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) {
        NutritionFacts cocaCola =
                new NutritionFacts(240, 8, 100, 0, 35, 27);
    }

위와 같이 점층적 생성자 패턴(Telescoping Constructor Pattern) 이 된다.
이는 생성자 체이닝 방식 이라고도 불린다.

  • 장점
    중복코드를 줄일 수 있다.

  • 단점
    확장이 어렵다.
    IDE에 도움이 없다면, 파라미터를 파악하기 어렵다.

자바빈즈 패턴(JavaBeans Pattern)

매개변수가 없는 기본 생성자를 생성하고 setter 메서드를 호출해 매개변수의 값을 설정하는 방식이다.

public class NutritionFacts { 
    // 기본값이 있다면, 매개변수들을 기본값으로 초기화된다.
    private final int servingSize  = -1;  // 필수, 기본값 없음
    private final int servings     = -1;  // 필수, 기본값 없음
    private final int calories     = 0;
    private final int fat          = 0;
    private final int sodium       = 0;
    private final int carbohydrate = 0;
    
    public NutritionFact () {}
    
    // 세터 메서드들
    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;}
    
}
  • 장점
    객체 생성이 간단해진다.

  • 단점
    일관성이 깨짐
    불변객체로 만들기 어렵다.

코드가 더 길어지긴 했지만 생성자와 정적 팩터리가 가지는 문제점들이 해결되는 것을 볼 수 있다.

하자만 자바 빈즈 패턴에는 치명적인 문제가 있다.

객체 하나를 만들기 위해서 메서드를 여러 개 호출해야 하고 객체가 완전히 생성되기 전까지 일관성이 무너진 상태에 놓이게 된다. 메서드 호출이 강제되지 않기 때문에 일관성이 무너진 상태에 있는 클래스를 어디서든 사용할 수 있게 된다. 반면에 점층적 생성자 패턴에서는 생성자에서 매개변수들이 유효한지를 확인하기 때문에 생성 시점에 일관성을 유지할 수 있다.

빌더 패턴 (Builder Pattern)

  • 사용자는 필수 매개변수만으로 생성자(혹은 정적 팩토리 메서드)를 호출해 빌더 객체를 얻는다.
  • 빌더 객체가 제공하는 (Setter 메서드와 유사한) 것으로 선택 매개변수를 주입한다.
  • 매개변수가 없는 build 메서드를 호출하여 필요한 객체를 얻는다.
    (빌더는 생성할 클래스 안에 정적 멤버 클래스로 만들어두는게 보통이다.)
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 static class Builder { 
        // 필수 매개변수
        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 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;
    }
}
  • 장점
    객체 생성에 유연하다.
    클라이언트에서 필요한 필드의 모든 경우를 선택적으로 생성 가능
    확장성이 뛰어나다.
    API는 시간이 지날수록 파라미터가 많아지기 때문에 확장성이 중요하다.

  • 단점
    필수 값을 지정할 수 없음
    생성자나 정적 팩터리가 처리해야 할 매개변수가 많다면 빌더 패턴을 선택하는 게 더 낫다.

참고

https://velog.io/@holidenty/이펙티브-자바-객체의-생성과-파괴-Item2-생성자에-매개변수가-많다면-빌더를-고려하라

0개의 댓글