요구사항
최첨단 피자 코드 만들기
•
피자 주문시 매개변수를 통해서 다양한 종류의 피자를 동적으로 생성하고 싶음!
•
다양한 스타일의 피자들이 생겨날 수 있음!
해결 방법 1 - 간단한 팩토리 만들기
피자의 생성 코드를 외부로 분리해서 객체 생성만을 처리하는 팩토리를 만들어냄
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("PepperoniPizza")) {
pizza = new PepperoniPizza();
} else {
pizza = new DefaultPizza();
}
return pizza;
}
}
Java
복사
•
객체 생성 캡슐화의 장점
◦
피자 객체 생성을 캡슐화 해놓으면 여기저기 고칠 필요 없이 팩토리 클래스 하나만고치면 됨
◦
서브클래스를 만들어서 메소드의 행동을 변경할 수 없음
◦
간단한 팩토리는 디자인 패턴이라기 보다는 프로그래밍에서 자주쓰이는 관용구에 가까움
•
팩토리 메소드를 static으로 만들면?
◦
팩토리 클래스의 인스턴스를 생성하지 않아도 됨
◦
서브클래스를 만들어 생성 메소드 행동 변경이 불가
해결 방법 2 - 팩토리 메서드 패턴 적용
생산자 클래스 다이어그램
제품 클래스 다이어그램
피자집이 대성하여 다양한 지점이 생기게 되었고, 각 지점은 지역 특성에 맞는 피자인 시카고 피자를 만들어야 하는 요구사항이 추가됨
•
이 문제를 해결하기 위해서 PizzaStore과 피자 제작코드 전체를 하나로 묶어주는 프레임워크를 만들어야 함
◦
물론 그렇게 만들면서도 유연성을 잃어버리면 안됨
•
createPizza() 메소드를 추상 메소드로 만들고 추상 클래스를 만들어 지역에 맞기 서브클래스를 만듦
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type);
}
Java
복사
•
모든 팩토리 패턴은 객체 생성을 캡슐화 함
•
팩토리 메소드 패턴은 서브클래스에서 어떤 클래스를 만들지 결정함으로써 객체 생성을 캡슐화 함
•
팩토리 메소드 패턴은 객체를 생성할 때 필요한 인터페이스를 만들어 냄
◦
어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정
해결 방법 3 - 추상 팩토리 패턴
추상 팩토리 패턴은 구상 클래스에 의존하지 않고 설 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공
•
구상 클래스는 서브 클래스에서 만들어 냄
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClams();
}
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();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = { new Farlic(), new Onion(), new Mushroom(), new RedPepper() };
return veggies;
}
@Override
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
@Override
public Clams createClams() {
return new Freshclams();
}
}
public class CheesePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
public void prepare() {
this.dough = ingredientFactory.createDough();
this.sauce = ingredientFactory.createSauce();
this.cheese = ingredientFactory.createCheese();
}
}
Java
복사
DIP
•
추상화된 것에 의존하게 만들고 구상 클래스에 의존하지 않게 만든다.
•
의존성 뒤집기 원칙에서는 추상화를 더 많이 강조함
•
이 원칙에는 고수준 구성요소가 저수준 구성 요소에 의존하면 안 되며, 항상 추상화에 의존하게 만들어야 한다는 뜻
◦
PizzaStore은 고수준 구성요소 피자 클래스는 저수준 구성 요소
•
의존성 뒤집기 원칙을 지키는 방법
◦
변수에 구상 클래스의 레퍼런스를 저장하지 말자
◦
구상 클래스에서 유도된 클래스를 만들지 말자
◦
베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드 하지 말자
정리
•
팩토리 메소드 패턴
◦
구상 형식을 서브클래스에서 처리해주니까 자신이 사용할 추상 형식만 알면 된다.
•
추상 팩토리 패턴
◦
제품근을 만드는 추상 형식을 제공, 서브클레스에서 정의