*Builder Pattern
Builder : 복잡한 구성의 객체를 효과적으로 생성하는 패턴
2가지의 서로 다른 내용이 있음
1. 생성 시 지정해야 할 인자가 많을 때 사용
2. 객체 생성 시 여러 단계를 순차적으로 거칠 때 이 단계의 순서를 결정해두고 각 단계를 다양하게 구현할 수 있도록 하는 패턴
< 1. 생성 시 지정해야 할 인자가 많은 경우>
Car 클래스는 생성 시 에어백 유무, 엔진, 색상, 카메라 센서 유무, AEB 유무 5개의 인자가 필요함.
Car 클래스 생성 시 new를 이용해 위 5개 인자를 넣기 대신, CarBuilder 클래스를 이용하는 방법을 사용할 수 있음.

5개의 인자를 가지는 Car 클래스
public class Car {
private String engine;
private boolean airbag;
private String color;
private boolean cameraSensor;
private boolean AEB;
public Car(String engine, boolean airbag, String color,
boolean cameraSensor, boolean AEB) {
this.engine = engine;
this.airbag = airbag;
this.color = color;
this.cameraSensor = cameraSensor;
this.AEB = AEB;
}
@Override
public String toString() {
SreingBuilder sb = new StringBuilder();
sb.append("CAR SPEC").append(engine).... // 차량 정보 출력하도록!
return sb.toString();
}
}
Car 객체를 생성하는 CarBuilder 클래스.
각 인자들을 set 하는 메서드와 Car 객체를 생성하는 build 메서드를 가지고 있다.
public class CarBuilder {
private String engine;
private boolean airbag;
private String color;
private boolean cameraSensor;
private boolean AEB;
public CarBuilder setEngine(String engine) {
this.engine = engine;
return this;
}
public CarBuilder setEngine(boolean airbag) {
this.airbag = airbag;
return this;
}
public CarBuilder setEngine(String color) {
this.color = color;
return this;
}
public CarBuilder setEngine(boolean cameraSensor) {
this.cameraSensor = cameraSensor;
return this;
}
public CarBuilder setEngine(boolean AEB) {
this.AEB = AEB;
return this;
}
public Car build() {
return new Car(engine, airbag, color, cameraSensor, AEB);
}
}
메서드를 연속적으로 호출하는 방식 : Method Cahining
이 방식을 사용하기 위해 CarBuilder 클래스의 set 메서드에서 this를 리턴함.
이를 통해 실제 객체 생성을 지연시킬 수 있음.
public class MainEntry {
public static void main(String[] args) {
Car car1 = new Car("V7", true, "Black", true, false);
Car car2 = new CarBuilder()
.setABE(false)
.setAirbag(false)
.setCameraSensor(true)
.setColor("White")
.setEngine("V9")
.build();
CarBuilder build = new CarBuilder() // 최종 Car 객체 생성을 지연
.setABE(false)
.setCameraSensor(true)
.setColor("White")
.setEngine("V9");
Random random = new Random();
Car car3 = builder
.setAirbag(random.nextInt(2) == 0) // 50% 확률로 aribag 유무 결정
.build(); // 최종 Car 생성
< 2. 객체 생성 시 여러 단계를 순차적으로 거칠 때 이 단 게의 순서를 결정해두고 각 단계를 다양하게 구현할 수 있도록 하는 패턴>
Builder : 추상 클래스, 무언가를 만드는 책임을 가짐. 만드는 메서드는 추상 클래스로 아래 Builder를 통해 구현
Director: Builder에서 제공하는 메서드들을 정해진 순서대로 호출
무언가를 만드는 Builder의 메서드를 구체적으로 구현
- PlainTextBuilder : Data 객체를 평범한 문자열로 만듦
- JSONBuilder : Data 객체를 JSON 형태의 문자열로 만듦
- XMLBuilder : Data 객체를 XML 형태의 문자열로 만듦

Data 클래스의 객체는 이름, 나이의 정보를 가지고 있음
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;
}
}
Data를 가공해 필요한 데이터로 만드는 Builder 추상 클래스.
public abstract class Builder {
protected Data data;
public Builder(Data data) {
this.data = data;
}
public abstract String head();
public abstract String body();
public abstract String foot();
// 위 매서드를 어느 순서로, 어떤 방식으로 진행할지는 Director 클래스가 정함
}
Builder클래스 메서드의 작동 순서, 방식을 정하는 Director 클래스
public class Director {
private Builder builder;
public Director(Builder builder) {
this.builder = builder
}
public String build() {
StringBuilder sb = new StringBuilder();
sb.append(builder.head());
sb.append(builder.body());
sb.append(builder.foot());
return sb.toString();
}
Builder 클래스를 상속하는 여러 클래스들
- PlainTextBuilder
public class PlainTextBuilder extends Buillder {
public PlainTextBuilder(Data data) {
super(data);
}
@Override
public String head() {
return "";
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("Name: ")
.append(data.getName())
.append(", Age: ")
.append(data.getAge());
return sb.toString();
}
@Override
public String foot() {
return "";
}
}
- JSONBuilder
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\": ")
.append("\"" + data.getName() + "\"")
.append(", \"Age\": ")
.append(data.getAge());
return sb.toString();
return
}
@Override
public String foot() {
return "}";
}
}
- XMLBuilder
public class XMLBuilder extends Builder {
public XMLBuilder(Data data) {
super(data);
}
@Override
public String head() {
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" endcoding=\"utf-8\"?>")
.append("<DATA>");
return sb.toString();
}
@Override
public String body() {
StringBuilder sb = new StringBuilder();
sb.append("<Name>")
.append(data.getName())
.append("</Name>")
.append("<Age>")
.append(data.getAge())
.append("</Age>");
return sb.toString();
}
@Override
public String foot() {
return "</DATA>";
}
}
구현한 클래스들을 활용해 출력하기
public class MainEntry {
Data data = new Data("Jane", 25);
Builder builder = new PlainTextBuilder(data);
Director director = new Director(builder);
String result = director.build();
System.out.println(result);
builder = new JSONTextBuilder(data);
director = new Director(builder);
result = director.build();
System.out.println(result);
builder = new XMLTextBuilder(data);
director = new Director(builder);
result = director.build();
System.out.println(result);
}
이 패턴은 Template, Facade, Strategy 패턴을 객체의 생성에 적용한 것으로도 볼 수 있음.
- Builder를 통해 무언가를 생성할 때 호출되는 메서드를 추상 메서드로 선언하고, 그 메서드를 각 파생 클래스에서 구현한 후 메서드의 호출 방식은 Director 클래스에서 정함 = Template Pattern
- Director 가 Facade의 역할로써 Builder매서드들의 사용을 단순화 : Facade Pattern
- 원하는 상황에 맞는 형식으로 변환하는 것 : Strategy Pattern
패턴은 그대로 사용하는 게 아니라 이해 후 다양하게 응용해서 사용하는 도구이므로 다양하게 패턴을 살펴보며 학습하자.
'코딩 > Software Architecture' 카테고리의 다른 글
| [GoF Design Pattern] Decorator (0) | 2022.12.05 |
|---|---|
| [GoF Design Pattern] Memento (0) | 2022.12.05 |
| [GoF Design Pattern] Facade (0) | 2022.12.04 |
| [GoF Design Pattern] Flyweight (0) | 2022.12.04 |
| [GoF Design Pattern] Command (0) | 2022.12.04 |