본문 바로가기

언어/Java

[ Java ] Builder Pattern - 빌더 패턴 알아보기

반응형

1. 빌더 패턴 (Builder Pattern)

1. 정의
빌더 패턴은 복잡한 객체를 단계별로 생성하고, 그 과정에서 객체의 다양한 옵션이나 속성을 유연하게 설정할 수 있게 해주는 디자인 패턴입니다. 빌더 패턴은 생성자(constructor)나 팩토리 패턴이 처리하기 힘든, 매개변수가 많은 복잡한 객체를 유연하게 만들 수 있습니다. 이 패턴은 특히 필수적인 속성과 선택적인 속성이 섞여 있을 때 유용합니다.

2. 목적

  • 객체 생성의 복잡성 감소: 생성자에서 많은 매개변수를 다루는 대신, 빌더 클래스를 통해 객체 생성의 복잡성을 줄입니다.
  • 유연한 객체 생성: 선택적인 속성을 쉽게 설정할 수 있고, 각 속성의 설정을 명시적으로 단계별로 처리할 수 있습니다.
  • 가독성 향상: 여러 매개변수가 있는 생성자나 메서드를 사용하는 대신, 빌더 패턴은 명확한 방식으로 매개변수를 설정할 수 있어 코드 가독성이 높아집니다.

3. 사용 예시
빌더 패턴은 다음과 같은 상황에서 사용됩니다:

  • 객체에 여러 개의 필수 및 선택적 속성이 있을 때
  • 여러 단계에 걸쳐 객체를 생성해야 할 때
  • 생성자의 매개변수가 너무 많아져 가독성이 떨어질 때

4. 구현 방법
자바에서는 보통 내부 클래스나 별도의 빌더 클래스를 통해 구현됩니다. 빌더 클래스는 객체가 가질 수 있는 속성을 메서드 체인 방식으로 설정하며, 최종적으로 객체를 반환합니다.

// 빌더 패턴을 구현한 예시

class House {
    // 집의 속성들
    private String foundation;
    private String structure;
    private String roof;
    private boolean hasGarage;
    private boolean hasSwimmingPool;
    private boolean hasGarden;

    // House 생성자의 접근 제어자를 private로 설정하여 직접 호출하지 않도록 함
    private House(Builder builder) {
        this.foundation = builder.foundation;
        this.structure = builder.structure;
        this.roof = builder.roof;
        this.hasGarage = builder.hasGarage;
        this.hasSwimmingPool = builder.hasSwimmingPool;
        this.hasGarden = builder.hasGarden;
    }

    // 집의 정보를 출력하는 메서드
    public void showInfo() {
        System.out.println("Foundation: " + foundation);
        System.out.println("Structure: " + structure);
        System.out.println("Roof: " + roof);
        System.out.println("Has Garage: " + hasGarage);
        System.out.println("Has Swimming Pool: " + hasSwimmingPool);
        System.out.println("Has Garden: " + hasGarden);
    }

    // 빌더 클래스
    public static class Builder {
        // 빌더에서 설정할 수 있는 속성들
        private String foundation;
        private String structure;
        private String roof;
        private boolean hasGarage;
        private boolean hasSwimmingPool;
        private boolean hasGarden;

        // 필수 속성들에 대한 설정 메서드
        public Builder setFoundation(String foundation) {
            this.foundation = foundation;
            return this;
        }

        public Builder setStructure(String structure) {
            this.structure = structure;
            return this;
        }

        public Builder setRoof(String roof) {
            this.roof = roof;
            return this;
        }

        // 선택적 속성들에 대한 설정 메서드
        public Builder setGarage(boolean hasGarage) {
            this.hasGarage = hasGarage;
            return this;
        }

        public Builder setSwimmingPool(boolean hasSwimmingPool) {
            this.hasSwimmingPool = hasSwimmingPool;
            return this;
        }

        public Builder setGarden(boolean hasGarden) {
            this.hasGarden = hasGarden;
            return this;
        }

        // House 객체를 생성하는 build() 메서드
        public House build() {
            return new House(this);
        }
    }
}

public class BuilderPatternDemo {
    public static void main(String[] args) {
        // 빌더를 사용해 객체를 단계별로 생성
        House house = new House.Builder()
                            .setFoundation("Concrete")
                            .setStructure("Wood")
                            .setRoof("Shingles")
                            .setGarage(true)  // 선택적 속성
                            .setSwimmingPool(true)  // 선택적 속성
                            .build();  // 최종적으로 객체를 생성

        house.showInfo();
    }
}

5. 장점

  • 객체 생성의 유연성: 객체의 필수 속성과 선택적 속성을 유연하게 설정할 수 있습니다. 예를 들어, House 클래스에서 setGarage()setSwimmingPool() 같은 선택적 속성을 설정할 수 있습니다.
  • 코드의 가독성 증가: 빌더 패턴은 명확한 메서드 체인 방식으로 객체의 속성을 설정하기 때문에, 여러 매개변수를 사용한 생성자보다 코드의 가독성이 뛰어납니다.
  • 객체 생성 과정의 분리: 빌더 클래스를 사용함으로써 객체 생성 과정이 명확하게 분리되며, 객체 생성 로직이 보다 체계적으로 관리됩니다.

6. 단점

  • 코드가 길어질 수 있음: 빌더 클래스를 정의하고 각 속성에 대해 설정 메서드를 만들어야 하므로, 코드가 다소 길어질 수 있습니다.
  • 복잡성 증가: 빌더 패턴은 복잡한 객체를 유연하게 생성하는 데 유리하지만, 간단한 객체의 경우 불필요하게 복잡성을 증가시킬 수 있습니다.

7. 빌더 패턴이 유용한 경우

  • 필수 속성과 선택적 속성이 명확히 구분되는 경우: 예를 들어, 객체의 몇 가지 속성만 필수적으로 설정하고 나머지는 선택적으로 설정할 수 있는 경우에 적합합니다.
  • 객체의 생성 과정이 복잡한 경우: 여러 단계에 걸쳐 객체를 생성하거나, 다양한 설정 값들을 유연하게 변경해야 할 때 유용합니다.
  • 변경 불가능(immutable)한 객체를 생성하는 경우: 빌더 패턴을 사용하면 변경 불가능한 객체를 생성할 수 있으며, 객체 생성 후에는 상태가 변경되지 않도록 할 수 있습니다.

빌더 패턴은 복잡한 객체 생성의 유연성을 높여주며, 객체 생성에 필요한 여러 속성을 단계별로 명확하게 설정할 수 있게 해줍니다. 특히 필수적인 값과 선택적인 값을 명확하게 구분하고 싶은 경우에 유용합니다.

반응형