객체를 만들기 위한 정보가 많을 때 일부 정보만 가지고 있다면 객체를 점진적으로 만들어 나가는 패턴으로 복잡한 객체를 단계적으로 구축하는 패턴이다.
1. 다음과 같은 Coffee 클래스가 있다 하자.
public class Coffee {
private String size;
private String milk;
private boolean mocha;
private boolean whip;
private boolean caramel;
public Coffee(String size) {
this(size, "No", false, false, false);
}
public Coffee(String size, String milk) {
this(size, milk, false, false, false);
}
public Coffee(String size, String milk, boolean mocha) {
this(size, milk, mocha, false, false);
}
public Coffee(String size, String milk, boolean mocha, boolean whip) {
this(size, milk, mocha, whip, false);
}
public Coffee(String size, String milk, boolean mocha, boolean whip, boolean caramel) {
this.size = size;
this.milk = milk;
this.mocha = mocha;
this.whip = whip;
this.caramel = caramel;
}
}
커피의 옵션과 토핑에는 사이즈, 우유, 모카, 휘핑 등 많은 옵션들이 있고 각각의 옵션에 따라 여러개의 생성자가 있다.
2. Coffe를 만드는 Client코드는 다음과 같이 된다.
public class Client {
public static void main(String[] args) {
Coffee coffee1 = new Coffee("Large");
Coffee coffee2 = new Coffee("Medium", "Almond");
Coffee coffee3 = new Coffee("Medium", "Soy", true, false, true);
}
}
코드를 보면 각각의 생성자의 요구되는 매개변수와 해당하는 변수들이 무엇을 뜻하는지 알기 힘드며 새로운 옵션을 추가하기 위해서는 생성자를 추가해야 한다.
1. Coffee
public class Coffee {
private String size;
private String milk;
private boolean mocha;
private boolean whip;
private boolean caramel;
public Coffee() {}
public void setSize(String size) {
this.size = size;
}
public void setMilk(String milk) {
this.milk = milk;
}
public void setMocha(boolean mocha) {
this.mocha = mocha;
}
public void setWhip(boolean whip) {
this.whip = whip;
}
public void setCaramel(boolean caramel) {
this.caramel = caramel;
}
}
2. CoffeeBuilder
public class CoffeeBuilder {
private Coffee coffee;
public CoffeeBuilder(String size) {
coffee = new Coffee();
coffee.setSize(size);
}
public CoffeeBuilder milk(String milk) {
coffee.setMilk(milk);
return this;
}
public CoffeeBuilder mocha(boolean mocha) {
coffee.setMocha(mocha);
return this;
}
public CoffeeBuilder whip(boolean whip) {
coffee.setWhip(whip);
return this;
}
public CoffeeBuilder caramel(boolean caramel) {
coffee.setCaramel(caramel);
return this;
}
public Coffee build() {
return coffee;
}
}
3. Client
public class Client {
public static void main(String[] args) {
Coffee coffee = new CoffeeBuilder("Large").milk("Almond")
.whip(true).build();
}
}
문제 상황과는 다르게 어떤 속성에 어떤 값이 매칭되는지 보기 쉽다.
빌더 패턴을 사용함으로 얻을 수 있는 효과 중 하나는 필수 초기화 변수
와 초기화를 하지 않아도 되는 변수
를 구분할 수 있다는 점이다. 위 예제로는 size
가 필수 초기화 변수
이고 나머지 가 초기화를 하지 않아도 되는 변수
이다.
필수 초기화 변수
는 Builder 생성시에도 필요한 변수로, Builder를 생성할 때 값을 넘겨준다.초기화를 하지 않아도 되는 변수
는 이후 Builder의 buildPart 메소드를 통해 Set해준다.