헤드 퍼스트 디자인 패턴을 읽고 정리한 글입니다.
추상 팩토리 패턴(Abstract Factory Pattern)은 서로 연관된, 또는 의존적인 객체들로 이루어진 제품군을 생성하기 위한 인터페이스를 제공합니다. 구상클래스는 서브 클래스에 의해 만들어집니다.
다음은 팩토리 메소드 패턴 예제 와 비슷한 피자를 주문하는 예제이다. (소스 코드가 길어 팩토리 메소드 패턴 예제와 중복된 부분은 생략하였다.)
피자 재료를 만드는 팩토리 인터페이스 PizzaIngredientFactory이다. 간단히 도우와 소스를 생성하도록 만들었다.
public interface PizzaIngredientFactory {
Dough createDough();
Sauce createSauce();
}
PizzaIngredientFactory를 확장해 두 팩토리 구성 클래스를 만들고 createDough와 createSauce 메소드를 구현하였다.
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
}
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new PlumTomatoSauce();
}
}
NYPizzaStore는 각 피자를 만들 때 사용할 재료를 만들기 위해 쓸 피자 재료 공장 각 객체에 전달 해준다.
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}
return pizza;
}
}
간단히 Dough와 Sauce를 만들어 보았다.
public interface Dough {
String getName();
}
public class ThinCrustDough implements Dough {
@Override
public String getName() {
return "ThinCrustDough";
}
}
public interface Sauce {
String getName();
}
public class MarinaraSauce implements Sauce {
@Override
public String getName() {
return "MarinaraSauce";
}
}
public class PlumTomatoSauce implements Sauce {
@Override
public String getName() {
return "PlumTomatoSauce";
}
}
이제 CheessePizza에서는 전달받은 피자 재료 공장을 이용해 도우와 소스를 생성한다.
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
System.out.println("preparing~~ " + name + ", "
+ dough.getName() + ", " + sauce.getName());
}
}
main 메소드에서 예제를 실행해보자.
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
nyStore.orderPizza("cheese");
nyStore.orderPizza("veggie");
chicagoStore.orderPizza("cheese");
chicagoStore.orderPizza("veggie");
preparing~~ New York Style Cheese Pizza, ThinCrustDough, MarinaraSauce
baking~~
boxing~~
preparing~~ New York Style Veggie Pizza, ThinCrustDough, MarinaraSauce
baking~~
boxing~~
preparing~~ Chicago Style Cheese Pizza, ThinCrustDough, PlumTomatoSauce
baking~~
boxing~~
preparing~~ Chicago Style Veggie Pizza, ThinCrustDough, PlumTomatoSauce
baking~~
boxing~~
예상한대로 재료가 만들어진 걸 볼 수 있다.
팩토리 메소드 패턴과 추상 팩토리 패턴은 상속
혹은 구성
을 활용하는 차이가 있지만, 둘다 객체를 만드는 일을 하며 애플리케이션의 구상 클래스에 대한 의존성을 줄여줌으로써 느슨한 결합을 도와준다.