이펙티브 자바[아이템2]

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

생성자에 매개변수가 많다면 코드가 상당히 지저분해진다. 또한 생성자의 종류가 많을수록 중복되는 코드가 늘어난다.
이럴땐 this()키워드를 통해 생성자 체이닝을 고려할 수 있다.

  • 이는 매개변수가 적은 부분에서 같은 클래스내의 다른 생성자를 호출하는 것이다
  • IDE의 도움이 없다면 객체를 생성할 때 어떤 파라미터를 넘겨줘야하며, 어떤 필드에 값이 들어가는지 체이닝을 타고가기 때문에 파악하기 까다롭다.

혹은 클래스 내의 필수값을지정하기 어려울 수 있다. 때문에 다른 대안으로 자바빈즈 패턴을 사용할 수 있다.(추후 설명)

  • 완벽한 객체를 만드려면 setter를 여러번 호출해야한다.
  • setter를 제공하기 때문에 클래스를 불변으로 만들 수 없다.

Builder

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

이렇게 빌더를 만들면 객체의 필수값을 필수로 지정함과 동시에 immutable한 객체를 만들 수 있다.

public static void main(String[] args) {
    NutritionFacts build = new Builder(100, 10)
                .fat(25)
                .calories(300)
                .sodium(100)
                .carbohydrate(100)
                .build();
}
  • 메서드 체이닝을하여 점층적 생성자보다 클라이언트 코드를 읽기가 훨씬 간결하고, 자바빈즈보다 훨씬 안전하다.

  • 그러나 빌더를 위해 너무 많은 코드를 작성해야함.
    (Lombok을 통해 빌더 자동생성 가능)

  • 그러나 Lombok을 통해 자동생성되는 빌더는 빈 아규먼트 생성자를 생성하여 필수값을 지정할 수 없음

자바빈

(주로 GUI에서) 재사용 가능한 소프트웨어 컴포넌트를 위한 규약이라고 생각하면 됨

  • java.beans 패키지 안에 있는 모든 것
  • 그 중에서도 자바빈이 지켜야 할 규약
    • 아규먼트 없는 기본 생성자
    • getter와 setter 메소드 이름 규약
    • Serializable 인터페이스 구현
  • JPA나 스프링에서는 리플렉션을 사용하여 객체를 조회하거나 설정하기 때문에 자바빈즈 규약을 지켜 getter와 setter를 생성하는 것이 중요