1. 빌더 패턴이란?
빌더 (Builder) 패턴은 복잡한 구성의 객체를 효과적으로 생성하는 패턴
빌더 패턴의 종류는 2가지
- 생성시 지정해야 할 인자가 많을 때 사용하는 패턴
- 객체 생성 시 여러 단계를 순차적으로 거칠 때, 이 단계의 순서를 결정해 두고 각 단계를 다양하게 구현할 수 있도록 하는 패턴
대부분 빌더 패턴은 첫번째 종류로만 이해하는 경우가 대부분
빌더 패턴외에 객체 생성 패턴은 대표적으로 점층적 생성자 패턴, 자바 빈즈 패턴이 존재
점층적 생성자 패턴 - 생성자를 매개변수에 갯수만큼 구성하는 패턴
자바 빈즈 패턴 - 별도의 생성자를 구성하지 않고 객체를 생성한 후, Setter를 이용하여 객체를 구성하는 형태를 의미
2. 생성시 지정해야 할 인자가 많을 때 사용하는 패턴
public class Car {
private String engine;
private boolean airbag;
private String color;
public Car(String engine, boolean airbag, String color) {
this.engine = engine;
this.airbag = airbag;
this.color = color;
}
}
public class CarBuilder {
private String engine;
private boolean airbag;
private String color;
public CarBuilder setEngine(String engine) {
this.engine = engine;
return this;
}
public CarBuilder setAirbag(boolean airbag) {
this.airbag = airbag;
return this;
}
public CarBuilder setColor(String color) {
this.color = color;
return this;
}
public Car build() {
return new Car(engine, airbag, color);
}
}
위 빌더 패턴 코드를 보면 setMethod에서 자신을 return 하고 있다. 이는 연속적으로 자신을 호출하고 있다.
이런 방식은 마치 메서드가 체인처럼 엮여있는것 같다 하여 Method Chaining이라고 한다.
작성한 빌더 패턴을 사용한 예시
public static void main(String[] args) {
SpringApplication.run(NewsongPickerApplication.class, args);
// 클래스 생성자
Car car1 = new Car("A7", true, "Black");
// 빌더 패턴 사용
Car car2 = new CarBuilder()
.setEngine("B7")
.setAirbag(true)
.setColor("White")
.build();
}
위 빌더 패턴을 사용함으로 두가지 이점을 얻을 수 있다.
1. 생성자를 이용한 객체 생성시 정해진 순서에따라 파라미터를 매핑 해줘야하는 번거로움이 존재하지만, 빌더 패턴을 통해 순서와 상관없이 객체 생성에 필요한 파라미터를 세팅해줄 수 있다.
2. 생성자를 이용한 객체 생성시 내가 작성한 파라미터가 정해진 위치에 입력되었는가에 대한 확인이 어렵다. 빌더 패턴을 사용할 경우 setXXX 형태의 메서드를 호출함으로 내가 어떤 객체 필드에 파라미터를 매핑시키고 있는지를 직관적으로 확인할 수 있다.
3. 생성자를 이요한 객체 생성시 생성자의 호출과 동시에 객체를 생성해야하지만, 빌더 패턴 사용시 객체 생성 시점을 나중으로 미룰 수 있다. (build 메서드의 호출을 나중으로 미룸으로 가능)
3. 정해진 순서를 다양하게 구현 할 수 있도록 하는 패턴
빌더 패턴의 두번째 패턴은 객체를 생성할 때 여러 단계를 순차적으로 거치며 생성할 필요가 있는 경우, 이 단계의 순서를 미리 정해두고 각 단계를 다양하게 구현할 수 있도록 하는 패턴
아래는 위 패턴을 구현하기 위한 예시 클래스 다이어그램
Builder 클래스는 추상클래스이다.
Builder 클래스를 상속받는 클래스들은 Builder 클래스에 선언되어 있는 추상메서드를 구현해야하는 책임이 있다.
위 클래스 다이어그램 구현 코드
public class Data {
private String name;
private int age;
public Data(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public abstract class Builder {
// 자식 클래스에 해당 필드를 사용해야 함으로 Protected
protected Data data;
public Builder(Data data) {
this.data = data;
}
// 아래 3개의 메서드를 이용하여 원하는 기능을 동작시킨다.
// 이 때 어떤 순서와 어떤식으로 메서드를 사용할지는 Director 클래스가 책임진다.
public abstract String head();
public abstract String body();
public abstract String foot();
}
public class Director {
// Builder 추상 클래스를 구현한 Concrete Class 들이 Dirctor 클래스가 생성되는 시점에 필드에 세팅된다.
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
public String build() {
StringBuilder sb = new StringBuilder();
// Builder를 이용하여 Builder 메서드를 순차적으로 호출 하고 있다.
// 여기서 순서는 Director 클래스가 필요에 따라 정한다.
sb.append(builder.head());
sb.append(builder.body());
sb.append(builder.foot());
return sb.toString();
}
}
Builder 추상 클래스의 구현 클래스 PlainTextBuilder
public class PlainTextBuilder extends Builder{
public PlainTextBuilder(Data data) {
super(data);
}
@Override
public String head() {
return "";
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("Name: ");
sb.append(data.getName());
sb.append(", Age: ");
sb.append(data.getAge());
return sb.toString();
}
@Override
public String foot() {
return "";
}
}
Builder 추상 클래스의 구현 클래스 JsonBuilder (XMLBuilder 클래스 생략)
public class JSONBuilder extends Builder {
public JSONBuilder(Data data) {
super(data);
}
@Override
public String head() {
return "{";
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("\"Name\": ");
sb.append("\"" + data.getName() + "\"");
sb.append(", \"Age\": ");
sb.append(data.getAge());
return sb.toString();
}
@Override
public String foot() {
return "}";
}
}
위와 같이 형태의 빌더 패턴을 구현 할 경우, Builder 추상 클래스가 동작해야할 기능을 메서드로 명시해두고 Director 클래스는 Builder 클래스가 제공하는 기능들의 순서를 정의한다.
이후 Director 클래스의 객체 생성시 Builder 추상 클래스를 구현한 구현 클래스를 인자로 넣게 될 경우, 해당 구현 클래스가 Builder 클래스의 정의된 메서드에 따라 구현한 기능들이 Director 클래스가 정의한 기능 순서에 따라 동작하게 된다.
위 형태의 Builder 패턴은 단순히 Builder 패턴이라기 보다, Facade 패턴, Template Method 패턴, Strategy 패턴등이 혼용되어 있다고 볼수도 있다.
Director는 Facade 패턴으로 볼수 있으며,
Builder를 통해 무언가를 생성할때 호출되는 메서드를 추상메서드로 선언하고, 각 메서드를 파생 클래스에서 구현하도록 한뒤 Director에서 순서를 정하도록 한 것은 Template Method 패턴의 응용로 볼 수 있다.
또한 원하는 상황에 따라 파생 클래스를 인자로 사용하는 부분은 Strategy 패턴이라고 볼 수 있다.
참고 문서
https://www.youtube.com/watch?v=sg_6GWRBRas
'Software Engineering' 카테고리의 다른 글
[디자인패턴] 팩토리 메서드(Factory Method) 패턴 (0) | 2024.04.16 |
---|---|
[디자인패턴] 어댑터(Adapter) 패턴 (0) | 2024.04.12 |
[디자인패턴] 전략(Strategy) 패턴 (0) | 2024.04.10 |