문제 제기
- 지난시간(링크). 우리는 피자가게 스토리와 엮어서 Factory Method Pattern에 대해 알아보았다.
- KorPizzaStore, IndiaPizzaStore를 만들어 Pizza 객체를 생성하는 createPizza에 대한 메소드는 Localize 된 피자스토어에 맡겼다. (India에서는 피자를 손으로 찢어먹기때문에 cutting 하지 않는다는 상황가정때문)
- IndiaPizzaStore에서는 cheese를 파니르(채식) 치즈와 채식 도우와 닭고기 불고기 토핑을 쓴다고 한다.
- 이런 차이를 극복하기위해 Abstaract Factorty Pattern을 써서 KorPizzaStore와 다르게 재료생산해보자.
- 위와같이 피자마다 같은구성요소를 가지긴 하지만, 지역마다 다른 방식으로 구성요소를 구현한다. 또한 위의 3재료뿐만아니라 피자마다 추가로 새로운 토핑 및 향신료도 추가될 수 있을것이다.
Abstract Factory Pattern을 스토리에 적용시켜보자.
public interface PizzaIngredientFactory {
public Dough createDough();
public Cheese createCheese();
public Boolgogi createBoolgogi();
//이건 지역별로 함께 쓸 수 있다.
public Veggies[] createVeggies();
}
- 먼저 추상화된 재료 Pizza 재료 공장을 만들고, 지역별로 공장을 만들어보자.
- 도우, 불고기, 치즈는 다르지만, 베지는 공통적으로 함께 쓸 수있다.
public class IndiaPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough createDough() {
return new VeggieDough();
}
@Override
public Cheese createCheese() {
return new VeggieCheese();
}
@Override
public Boolgogi createBoolgogi() {
return new ChickenBoolgogi();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom()};
return veggies;
}
}
public class KorIngredientPizzaFactory implements PizzaIngredientFactory{
@Override
public Dough createDough() {
return new OriginalDough();
}
@Override
public Cheese createCheese() {
return new OriginalCheese();
}
@Override
public Boolgogi createBoolgogi() {
// TODO Auto-generated method stub
return new BeefBoolgogi();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom()};
return veggies;
}
}
- 위와같은식으로 나라에따라 피자 ingredient Factory를 만들었다.
- 이제 재료를 생산할 준비가 끝났다. 피자에 따라 재료가 달라지니 한번 Pizza Class를 바꿔보도록 하자.
public abstract class Pizza {
String name;
Dough dough;
Cheese cheese;
Boolgogi boolgogi;
Veggies veggies[];
//원재료 생산공장을 달리하면서 추상화시켯다.
public abstract void preare();
public void bake() {
System.out.println("굽는중.....");
}
public void cut() {
System.out.println("자르는중.....");
}
public void box() {
System.out.println("박싱중.....");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- prepare와 원재료들을 변수 이외에는 달라진 로직은 없다. 그러면 Boolgogipizza 클래스를 한번 만들어보자.
public class BoolGogiPizza extends Pizza {
PizzaIngredientFactory pizzaIngredientFactory;
public BoolGogiPizza(PizzaIngredientFactory pizzaIngredientFactory) {
setName( " Korea Style Cutting Pizza");
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare() {
System.out.println("재료준비중... " +name);
dough = pizzaIngredientFactory.createDough();
cheese = pizzaIngredientFactory.createCheese();
boolgogi = pizzaIngredientFactory.createBoolgogi();
System.out.println(dough.getClass().getSimpleName());
System.out.println(cheese.getClass().getSimpleName());
System.out.println(boolgogi.getClass().getSimpleName());
}
}
- 전 포스팅에서는 KorKorBoolGoggiPizza, IndiaBoolGoggiPizza 등, 구체적으로 로컬별 피자객체를 만들었으나, 이제는 ingredient Factory만 달리 생성하면 되므로 이런식으로 BoolGogiPizza 객체를 만들었다.
-다만 이제 KorPizzaStore에서 피자객체를 생성할때 코드가 바뀌어야한다..
//바뀌기전
public class KorPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza= null;
if(type.equals("boolgogi")) {
pizza = new KorBoolGoggiPizza();
}
return pizza;
}
}
//바뀐후
public class KorPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
Pizza pizza= null;
PizzaIngredientFactory fac = new KorIngredientPizzaFactory();
if(type.equals("boolgogi")) {
pizza = new BoolGogiPizza(fac);
pizza.setName("Korea Style Pizza From KOR ingredient Factory");
}
return pizza;
}
}
- 바뀌기전에는 피자 자체를 store에서 생성해주었지만, 이제는 원재료를 로컬별 IngredientPizzaFactory에서 받아쓰기때문에, IngredientPizzaFactory 객체를 BoolGogiPizza 생성자에 넘겨주어 피자 재료를 달리생성하게된다.
- 전 포스팅한 메인함수를 그대로 실행시켜보니 내가 의도한대로 잘 나온다.
Abstract Factory Pattern 내용 정리
- 지역별 PizzaStore에 피자라는 Product가 종속되어 있지않고, Abstract된 Ingredient Pizza Factory에 따라 제품을 받아쓰기 때문에, 프로그램이 실행중에도, 같은 불고기피자라도 다른 재료를 적용 시킬 수 있다.
Abstarct Factory Pattern 정의
추상 팩토리 패턴
추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된, 또는 서로 의존하는 객체를 구상 클래스를 지정하지 않고도 생성 할 수있다.
- 추상 팩토리 패턴을 이용하면, 인터페이스를 통해 Product 들을 생성 할 수있다.
(pizza = new BoolgogiPizza(korPizzaIngredientFactory); 처럼 말이다.)
- 따라서 클라이언트와 Product를 분리시킬수가 있다.
- 위와같은 클래스 다이어그램으로 Abstract Factorty Pattern을 표현할 수 있다.
- 실제 우리가 만든 피자스토어의 클래스다이어그램은 이렇게 만들 수 있다.
Abstract Factory Pattern Vs Factory Method Pattern
- Abstract Factory Pattern은 Factory Method Pattern에 비해 다소 복잡하다.
- 새로운 Product를 추가하려면 Factory Method Pattern는 Interface를 바꿔야 한다. (India boolgogi Pizza에서 Original Dough를 쓰고싶다면?? 코드자체가 바뀌어야함)
- Abstract Factory Pattern에서는 소스코드 자체를 추가하지않고, 구현체만 갈아끼우면 해결 할 수있다.
'To be Developer > DesignPatterns' 카테고리의 다른 글
6-1.Command Pattern (Simple) (0) | 2020.01.10 |
---|---|
5.Singleton Pattern (0) | 2020.01.07 |
4-1.Factory Pattern (Factory Method Pattern) (0) | 2020.01.04 |
3.Decorator Pattern (0) | 2020.01.02 |
2.Observer Pattern (0) | 2020.01.01 |