구상 클래스 생성 캡슐화

피자 가게 클래스에는 여러가지 피자 객체를 직접 생성하는 클래스가 있다.

Pizza orderPizza(String type) {

	Pizza pizza;
	
	if (type.equals("cheese")) {
		pizza = new CheesePizza();
	} else if (type.equals("greek")) {
		pizza = new GreekPizza();
	} else if (type.equals("pepperoni")) {
		pizza = new PapperoniPizza();
	}
	
	pizza.bake();
	pizza.box();
	return pizza;
}

이 클래스의 문제점은, 피자 구상 클래스의 종류가 늘어날 때마다 코드를 수정해주어야 하는 부분이다.

피자 구상 클래스를 만들어주는 팩토리 클래스를 만들어보자.

public class SimplePizzaFactory {

	public Pizza createPizza(String type) {
		Pizza pizza;
	
		if (type.equals("cheese")) {
			pizza = new CheesePizza();
		} else if (type.equals("greek")) {
			pizza = new GreekPizza();
		} else if (type.equals("pepperoni")) {
			pizza = new PapperoniPizza();
		}
		return pizza;
	}
}
Pizza orderPizza(String type) {

	Pizza pizza = new SimplePizzaFactory().createPizza(type);
	
	pizza.bake();
	pizza.box();
	return pizza;

이렇게 할 경우 피자 객체를 생성하는 모든 코드에서 피자 종류가 늘어나더라도 수정해야 할 필요가 없어지게 된다.

팩토리 메서드

여러 종류의 피자 가게 (뉴욕 스타일, 시카고 스타일 등등)이 있을 경우, 각 피자 가게별로 조금씩 다른 차이점을 어떤 식으로 적용해야 할까?

위에서 만든 SimplePizzaFactory를 빼고 서로 다른 피자 팩토리 클래스를 만들어서 피자 가게 클래스에 주입시켜주면 되지 않을까?

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("cheese");

다음과 같은 방법도 사용할 수 있다.

피자 팩토리와 피자 스토어를 하나로 묶고, 공통 로직을 넣은 후, 피자 생성 부분만 구현하도록 하는 것이다.

public abstract class PizzaStore {

	Pizza orderPizza(String type) {
	
		Pizza pizza = createPizza();
		
		pizza.bake();
		pizza.box();
		return pizza;
	}
	
	abstract Pizza createPizza(String type);
}

피자 가게 추상 클래스 안에 createPizza 추상 메서드를 만들고, 각 피자 분점 구상 클래스에서 해당 메서드를 구현하는 방식이다.

public class NYPizzaStore extends PizzaStore {
	Pizza createPizza(String item) {

		if (item.equals("cheese")) {
			return new NYStyleCheesePizza();
		} else if (item.equals("greek")) {
			return new NYStyleGreekPizza();
		} else if (item.equals("pepperoni")) {
			return new NYStylePapperoniPizza();
		} else {
			return null;
		}
	}
}

위와 같은 방식을 팩토리 메서드 패턴이라고 한다.