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

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


📂 item02_builder_pattern.md

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

🧩 빌더(Builder) 패턴이란?

  • 빌더 패턴(Builder Pattern)은 객체를 만들 때 매개변수가 많을 경우 유용하게 쓰이는 디자인 패턴입니다.

  • 생성자에 너무 많은 매개변수가 들어가면 코드가 복잡하고 가독성이 떨어지는데, 빌더 패턴은 이러한 문제를 해결해 줍니다.


📌 생성자에 매개변수가 많을 때의 문제점

객체를 생성할 때 아래의 문제들이 발생할 수 있습니다.

  • 점층적 생성자 패턴 (Telescoping Constructor Pattern)

    • 생성자를 여러 개 만들고, 매개변수를 조금씩 다르게 해서 여러 개를 정의하는 방식.

    • 단점: 코드가 길고, 읽기 어렵고, 순서를 잘못 넣기 쉬움.

예시 코드

NutritionFacts coke = new NutritionFacts(240, 8, 100, 0, 35, 27);
// 각 숫자의 의미를 알기 어렵다.
  • 자바빈즈(JavaBeans) 패턴

    • 객체를 먼저 만들고, 세터(setter)를 사용하여 나중에 값을 설정하는 방식.

    • 단점: 객체 생성과 값 설정이 분리되어, 값이 완전하지 않은 상태로 객체가 사용될 수 있음.

예시 코드

NutritionFacts coke = new NutritionFacts();
coke.setServingSize(240);
coke.setServings(8);
coke.setCalories(100);
// 값 설정이 누락될 가능성이 높음!

✅ 빌더 패턴의 장점 및 핵심 개념

1️⃣ 명확한 코드 작성 가능

  • 빌더 패턴은 매개변수의 이름을 명시적으로 보여줌으로써 코드가 읽기 쉬워집니다.

빌더를 활용한 객체 생성 예시

NutritionFacts coke = new NutritionFacts.Builder(240, 8)
                .calories(100)
                .sodium(35)
                .carbohydrate(27)
                .build();
  • 메서드가 연쇄적으로 연결되는 방식(method chaining)이라 코드의 의미가 명확해짐.


2️⃣ 빌더 패턴의 기본 구조

빌더 패턴은 클래스 내부에 **정적 내부 클래스(static inner class)**로 정의하여 사용합니다.

public class NutritionFacts {
    // 필수 멤버 변수
    private final int servingSize;
    private final int servings;

    // 선택 멤버 변수 (기본값 설정 가능)
    private final int calories;
    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 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 sodium(int val) {
            sodium = val;
            return this;
        }

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

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

    // Builder를 받아 객체를 생성하는 private 생성자
    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

🛠️ 빌더 패턴을 언제 사용하면 좋을까?

  • 클래스의 생성자나 정적 팩터리가 처리해야 할 매개변수가 많을 때

  • 매개변수 중 일부만 필수이고 나머지는 선택적일 때

  • 특히 매개변수가 많거나 같은 타입의 매개변수가 여러 개 있을 때


📌 빌더 패턴의 장점

  • 가독성: 매개변수가 많아도 각 값이 어떤 의미인지 명확하게 보입니다.

  • 유연성: 선택적인 매개변수 처리가 매우 편리합니다.

  • 안정성: 객체가 생성된 후에는 변경되지 않게 만들어(불변성) 안정성을 높입니다.

  • 계층적 설계에 유리: 상속이 많아도 깔끔한 코드 유지가 가능합니다.


⚠️ 빌더 패턴의 단점

  • 구현의 복잡성: 초기 구현 시 클래스와 빌더 클래스를 따로 만들어야 합니다.

  • 코드 길이 증가: 클래스가 작고 단순할 경우, 오히려 빌더 패턴이 더 번거로울 수 있습니다.


📚 핵심 용어

  • 빌더 패턴 (Builder Pattern): 객체를 만들 때 빌더 객체를 따로 두고 생성 과정을 깔끔하게 정리하는 방법.

  • 메서드 체이닝 (method chaining): 메서드가 계속 이어져서 호출되는 형태.

  • 플루언트 API (fluent API): 코드가 자연스럽게 읽히도록 메서드를 연쇄적으로 연결하는 스타일.

  • 불변 객체 (immutable object): 생성 후 상태가 변하지 않는 객체로, 안정성이 높음.


✨ Nutshell (한눈에 요약)

  • 빌더 패턴은 매개변수가 많은 객체를 명확하게, 안전하게, 편리하게 생성하는 디자인 방법입니다.

  • 빌더를 사용하면:

    • 매개변수가 많은 객체도 쉽게 생성 가능

    • 가독성과 유지보수성을 높이고 휴먼 에러를 방지

    • 코드가 명확해지고 직관적이 됩니다.

🔑 한 줄 결론: 매개변수가 많고 복잡한 클래스는 빌더 패턴을 쓰면 코드가 명확해지고 실수가 줄어듭니다.

Last updated