빌더 패턴

접근

  • 많은 필드와 중첩된 객체들을 단계별로 초기화해야 할 때 많은 매개 변수를 포함한 거대 생성자를 사용하면 코드가 복잡해진다.

  • 반드시 필요하지 않은 값들도 매개 변수로 정의되므로 null을 입력해야만 하는데, 이러면 가독성이 안좋아진다.

  • 객체 생성 코드를 추출해 빌더 클래스에 단계 별로 구성 요소를 생성하도록 해야 한다.

개념

  • 클라이언트가 객체를 생성할 때 다양한 방법으로 생성할 수 있도록 빌더 클래스를 제공하는 패턴이다.

  • 복합 객체 구조를 생성할 때 많이 쓰인다.

  • 아래와 같이 Builder 인터페이스를 구현하여 다양한 생성 단계를 가진 빌더 객체를 만들 수 있다. 각 빌더 객체로부터 얻은 결과 객체는 같은 클래스 계층구조 또는 인터페이스에 속할 필요가 없다. 디렉터 클래스를 생성하면 빌더 객체로 객체를 생성하는 방법을 캡슐화할 수 있다.

  • 아래와 같이 점층적 생성자로 인해 코드가 복잡해질 경우 빌더 패턴을 사용해 클라이언트가 필요한 단계들만 설정해 객체를 생성하도록 하면 된다.

  • 빌더의 생성 단계들을 재귀적으로 동작하도록 하여 컴포지트 패턴의 트리를 생성할 수 있다.

장단점

  • 장점

    • 복합 객체 생성 과정을 캡슐화한다.

    • 팩토리 패턴과 달리 여러 단계와 다양한 절차를 거쳐 객체를 만들 수 있다.

    • 클라이언트는 추상 인터페이스만 볼 수 있으므로 실제 빌더 구현체를 쉽게 바꿀 수 있다.

  • 단점

    • 팩토리를 사용할 때 보다 클라이언트에 관해 많이 알아야 한다.

사용 방법

  • 객체의 공통 생성 단계를 정의하고 빌더 인터페이스에서 이를 선언한다.

  • 빌더 인터페이스를 구현하는 클래스를 만든다. 필요하다면 디렉터 클래스도 만든다.

  • 클라이언트 코드에서 빌더 객체나 디렉터 객체를 사용해 원하는 객체를 생성한다.

예시

  • 아래에서 소개할 두 예시는 사실 완벽한 GoF 빌더 패턴은 아니다. 보통 GoF에서 제시한 것 처럼 빌더 인터페이스와 구현체를 따로 두지 않고 간편하게 정적 내부 클래스로 빌더를 정의한다.

Spring Cacheable의 빌더

  • 빌더 클래스를 정적 내부 클래스로 선언하고, 빌더 객체를 얻기 위해 builder 정적 메서드를 제공한다.

  • 다양한 초기화 메서드를 사용해 원하는 값들을 설정하고 build 메서드를 호출하면 생성된 객체를 얻을 수 있다.

롬복의 @Builder

  • 아래와 같이 필요한 인자를 입력받는 생성자에 @Builder 어노테이션을 붙이면 컴파일 시 롬복이 자동으로 빌더 클래스를 추가해준다.

  • 아래는 컴파일 후 class 파일을 디컴파일해본 결과이며, 자동으로 UserBuilder 클래스가 생성된 것을 확인할 수 있다.

Last updated