빌더 패턴
IT위키
더 많은 작업
- 상위 문서: 소프트웨어 디자인 패턴
빌더 패턴(Builder Pattern)은 여러 부분으로 이루어진 복잡한 객체를 만드는 과정을 단계별로 나누고, 같은 생성 절차로 서로 다른 표현의 객체를 만들 수 있게 객체의 생성과 표현을 분리하는 GoF 생성 패턴이다.
생성자 하나로 객체를 만들려면 부품이 많을수록 매개변수가 길어지고, 순서나 생략 여부에 따라 생성자를 여러 개 두어야 한다. 빌더 패턴은 객체를 한 번에 만들지 않고, 빌더(Builder) 객체에 부품을 하나씩 만들어 붙이게 한 뒤 마지막에 완성품을 꺼낸다. 건축가가 같은 설계 순서로 블록을 조립하더라도 어떤 블록을 쓰느냐에 따라 다른 건물이 나오는 것에 비유된다.
GoF 는 23개 패턴을 목적에 따라 생성·구조·행위로 나누는데, 빌더는 객체를 만드는 방법을 다루므로 팩토리 메서드, 추상 팩토리, 프로토타입, 싱글톤과 함께 생성 패턴에 속한다. 구조 패턴(어댑터·브리지·컴포지트·데코레이터·퍼사드·플라이웨이트·프록시)이 아니다.
| 역할 | 설명 |
|---|---|
| Builder | 부품을 만드는 단계별 메서드(buildPartA, buildPartB …)를 선언한 인터페이스 |
| ConcreteBuilder | Builder 를 구현해 실제 부품을 만들고 조립하며, 완성품을 돌려주는 메서드(getResult)를 가진다 |
| Director | Builder 의 메서드를 정해진 순서로 불러 생성 절차를 진행한다. 어떤 ConcreteBuilder 를 쓰는지는 모른다 |
| Product | 만들어지는 복잡한 객체 |
Director 가 같은 순서로 단계를 부르더라도, 텍스트 문서를 만드는 빌더를 넘기면 텍스트가, HTML 을 만드는 빌더를 넘기면 HTML 문서가 나온다. 생성 절차와 결과의 표현이 분리되어 있기 때문이다.
자바에서는 매개변수가 많은 객체를 만들 때 메서드를 이어 부르는 빌더를 흔히 쓴다.
public class Pizza {
private final String size; // 필수
private final boolean cheese; // 선택
private final boolean bacon; // 선택
private Pizza(Builder b) {
this.size = b.size;
this.cheese = b.cheese;
this.bacon = b.bacon;
}
public static class Builder {
private final String size;
private boolean cheese, bacon;
public Builder(String size) { this.size = size; }
public Builder cheese() { this.cheese = true; return this; }
public Builder bacon() { this.bacon = true; return this; }
public Pizza build() { return new Pizza(this); }
}
}
// 사용: 필요한 부품만 골라 단계적으로 조립하고 마지막에 build()
Pizza p = new Pizza.Builder("L").cheese().bacon().build();
- 매개변수가 많아도 무엇을 넣는지 이름으로 드러나 읽기 쉽다
- 완성된 객체는 필드를 바꾸지 않는 불변 객체로 만들기 쉽다
- 자바의 StringBuilder 처럼 조금씩 덧붙인 뒤 마지막에 결과를 꺼내는 클래스도 같은 생각이다
- 생성 과정을 단계별로 통제할 수 있고, 같은 절차로 다른 표현을 만들 수 있다
- 생성 코드와 표현 코드가 분리되어 새 표현을 추가할 때 ConcreteBuilder 만 더하면 된다
- 클래스(빌더)가 늘어나 단순한 객체에는 오히려 번거롭다