문제 제기

- 지난시간(링크). 우리는 피자가게 스토리와 엮어서 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

+ Recent posts