복잡한 객체를 생성하는 방법과 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴
- Builder : 객체의 요소들을 생성하기 위한 추상 클래스
- ConcreteBuilder : Builder가 정의한 메서드 구현
- Director : Builder 인터페이스를 사용하는 객체를 합성
- Product : 생성할 복합 객체를 표현
카페음료를 만드는 과정을 구현한다고 가정해보자. 카페음료를 만들기 위해 필요한 재료들을 정해놓고(Builder), 바리스타가 해당 재료들을 섞어 카페음료를 만들어낼 수 있다(Director).
[Coffee.java]
public class Coffee {
private final String base;
private final String liquid;
private final String syrup;
private final int price;
public Coffee(String base, String liquid, String syrup, int price) {
this.base = base;
this.liquid = liquid;
this.syrup = syrup;
this.price = price;
}
@Override
public String toString() {
return "Coffee [" +
"base='" + base + '\'' +
", liquid='" + liquid + '\'' +
", syrup='" + syrup + '\'' +
", price=" + price +
']';
}
}
[CoffeeBuilder.java]
public interface CoffeeBuilder {
CoffeeBuilder base(String base);
CoffeeBuilder liquid(String liquid);
CoffeeBuilder syrup(String syrup);
CoffeeBuilder price(int price);
Coffee build();
}
[DefaultCoffeeBuilder.java]
public class DefaultCoffeeBuilder implements CoffeeBuilder {
private String base;
private String liquid;
private String syrup;
private int price;
@Override
public CoffeeBuilder base(String base) {
this.base = base;
return this;
}
@Override
public CoffeeBuilder liquid(String liquid) {
this.liquid = liquid;
return this;
}
@Override
public CoffeeBuilder syrup(String syrup) {
this.syrup = syrup;
return this;
}
@Override
public CoffeeBuilder price(int price) {
this.price = price;
return this;
}
@Override
public Coffee build() {
return new Coffee(base, liquid, syrup, price);
}
}
[CoffeeDirector.java]
public class CoffeeDirector {
private final CoffeeBuilder coffeeBuilder;
public CoffeeDirector(CoffeeBuilder coffeeBuilder) {
this.coffeeBuilder = coffeeBuilder;
}
public Coffee americano() {
return coffeeBuilder.base("espresso")
.liquid("water")
.price(2500)
.build();
}
public Coffee vanillaLatte() {
return coffeeBuilder.base("espresso")
.liquid("milk")
.syrup("vanillaSyrup")
.price(4000)
.build();
}
}
[Client.java]
public class Client {
public static void main(String[] args) {
CoffeeDirector barista = new CoffeeDirector(new DefaultCoffeeBuilder());
Coffee americano = barista.americano();
System.out.println("아메리카노 " + americano.toString());
Coffee vanillaLatte = barista.vanillaLatte();
System.out.println("바닐라라떼 " + vanillaLatte.toString());
CoffeeBuilder builder = new DefaultCoffeeBuilder();
Coffee latte = builder.base("espresso")
.liquid("milk")
.price(3500)
.build();
System.out.println("라뗴 : " + latte.toString());
}
}
lombok의 @Builder는 GoF의 빌더 패턴과 같지 않음