헤드 퍼스트 디자인 패턴을 읽고 정리한 글입니다.
추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있다.
뉴옥과 시카고에서 사용하는 재료 종류는 서로 다르다. PizzaStore 분점이 점점 생기면서 해당 분점들은 또 다른 자신들만의 재료들을 사용해야 될 것이다.
이렇게 서로 다른 종유릐 재료들을 제공하기 위해 원재료군을 처리할 방법을 생각해야한다.
따라서 이제 원재료를 생산하기 위한 공장을 만들어보자.
원재료 공장에서는 원재료군에 들어있는 반죽, 소스, 치즈 같은 각각의 원재료를 생산한다.
우선 모든 원재료를 생산할 팩토리를 위한 인터페이스를 정의해보자
public interface PizzaIngredientFactory {
Dough createDough();
Sauce createSauce();
Cheese createCheese();
Veggies[] createVeggies();
Pepperoni createPepperoni();
Clams createClam();
}
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
...
}
원재료 팩토리가 준비되고 Pizza 클래스에서 팩토리에서 생산한 원재료만 사용하도록 코드를 수정한다.
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Cheese cheese;
...
public void box() {
System.out.println("포장");
}
public void cut() {
System.out.println("커팅");
}
public void bake() {
System.out.println("굽기");
}
abstract void prepare();
}
public class CheesePizza extends Pizza {
private final PizzaIngredientFactory pizzaIngredientFactory;
public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) { // 생성자를 통해 원재료를 제공하는 팩토리를 주입받는다.
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
void prepare() { // 팩토리가 작동하는 부분
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}
}
앞선 예제에서 NYStyleCheesePizza
, ChicagoStyleCheesePizza
클래스를 기억해보자. 그 두 클래스를 살펴보면 지역별로 다른 재료를 사용한다는 것만 빼면 다른 점이 없다.
이제 피자 코드에서는 팩토리를 이용하여 피자에서 쓰이는 재료를 만든다.
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (type.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
} else if (type.equals("greek")) {
pizza = new GreekPizza(ingredientFactory);
}
return pizza;
}
}
기존 팩토리 패턴에서 추상 팩토리라고 부르는 새로운 형식의 팩토리를 도입해서 서로 다른 피자에서 필요로 하는 원재료군을 생산하기 위한 방법을 구축했다.
제품군을 만들 때 쓸 수 있는 추상 팩터리 패턴에서는 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있다.
추상 팩토리 패턴에 있는 createDough()
, createSauce()
같은 메서드는 전부 팩토리 메서드 같이 보인다.
그렇다면 추상 팩토리 패턴 뒤에는 팩토리 메서드 패턴이 숨어져 있는 것일까?
하지만 팩토리 메서드 패턴은 상속을 통해 객체를 생성하고 추상 팩토리 패턴은 객체 구성을 통해 객체를 생성한다.
또한 추상 팩토리 패턴에서는 제품군에 제품을 추가하는 식으로 관련 제품들을 확대해야 하는 경우에 인터페이스를 수정해야 하지만 팩토리 메서드 패턴에서는 한 가지 제품만 생산하므로 복잡한 인터페이스도 필요하지 않고, 메서드도 하나만 있으면 된다.