Factory Pattern은 객체를 생성하는 인터페이스를 정의한다.
subclass들이 어느 클래스를 인스턴스화할 지 결정하게 한다. 즉, subclass에게 인스턴스화를 위임한다.
Pizza 클래스가 있다. 피자를 조리할 때 pizza의 타입을 입력받고, 이에 따라 피자를 조리한다.(ex: cheese pizza)
만약, orderPizza 메소드에서 type을 입력받고, if 문을 이용하여 타입을 비교하고, 선택하는 것은 타입의 변화가 있을 때마다 코드를 변경해야 한다.
따라서, 이 행위를 해줄 Factory가 필요하다.
SimplePizzaFactory는 createPizza 메소드를 이용해 타입을 입력받고, 해당 타입에 맞는 피자 인스턴스를 반환한다.
PizzaStore 에서는 생성자에서 factory를 주입 받아 변수로 보유한다.
orderPizza 메소드에서는 type을 입력받은 후 factory의 createPizza 메소드에 전달하여 타입에 맞는 피자를 받는다.
이렇게 하면 타입에 맞게 pizza를 생성하는 코드를 구분할 수 있다.
특정 지역의 피자(NYStylePizza)를 추가로 관리하고 싶다면, PizzaStore를 abstract class로 변경한 후, createPizza를 abstract 메소드로 변경하면 된다. 각 지역의 PizzaStore에서 PizzaStore를 상속받은 후, 메소드를 알맞게 정의하면 된다.
Pizza 클래스는 name, dough 등을 변수로 가지며, prepare, bake 등의 피자를 만들 때 필요한 메소드를 가진다.
Pizza를 상속받은 클래스는 각 피자의 지역과 종류에 맞게 name, dough 등의 변수를 설정한다.
Pizza 클래스는 product class가 되고, PizzaStore 클래스는 Creator class, 즉, factory가 된다.
Design Principle
Depend upon abstractions. Do not depend upon concrete classes.
상위 레벨의 component가 하위 레벨의 component를 의존하면 안된다. 대신, 둘 다 추상화에 의존해야 한다.
-> dependency inversion
위 예에선 PizzaStore가 상위 레벨이고 Pizza가 하위 레벨이다.
위 원칙을 지키기 위해 코드를 변경해야 한다.
PizzaIngredientFactory 인터페이스를 생성한다. 이는 dough, sauce 등의 다양한 재료의 create 메소드를 가진다.
특정 지역의 ingeredientFactory는 PizzaIngredientFactory 를 구현하며, create(재료) 메소드를 해당 지역에 맞게 new로 생성한 후 반환한다.
Pizza 클래스는 dough, sauce 등의 재료들을 변수로 가지며 prepare 라는 abstract 메소드를 가진다.
각 피자 종류 객체(cheesePizza 같은)들은 PizzaIngredientFactory 변수를 가지며 생성자에서 이를 주입받는다.
또한, prepare 메소드에서 해당하는 ingredientFactory의 create(재료) 메소드를 이용해 dough, sauce 등의 재료들을 설정한다.
각 지역의 PizzaStore들은 createPizza 메소드에서 피자 종류를 주입받고 PizzaIngredientFactory 를 지역에 맞게 설정한다.
피자 종류를 구분하여 해당 피자 종류의 생성자에 지역에 맞는 PizzaIngredientFactory를 주입하여 지역과 종류에 맞는 피자를 생성하게 된다.
public abstract class Pizza {
public String name;
Dough dough;
Sauce sauce;
Cheese cheese;
Clams clam;
public abstract void prepare();
public void bake() {
System.out.println("baking");
}
public void cut() {
System.out.println("cutting");
}
public void box(){
System.out.println("boxing");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CheesePizza extends Pizza {
PizzaIngredientFactory pizzaIngredientFactory;
public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare() {
System.out.println("preparing " + name);
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
clam = pizzaIngredientFactory.createClam();
}
}
public class ClamPizza extends Pizza {
PizzaIngredientFactory pizzaIngredientFactory;
public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare() {
System.out.println("preparing " + name);
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
clam = pizzaIngredientFactory.createClam();
}
}
생성자에서 PizzaIngredientFactory를 주입받아, 지역을 결정한다.
지역에 맞는 dough, sauce, cheese, clam을 받는다.
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Clams createClam();
}
public class NTPizzaIngredientFactory 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 Clams createClam() {
return new FreshClams();
}
지역에 맞는 재료들을 반환한다.
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);
}
public class NYPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory nYIngredientFactory = new NTPizzaIngredientFactory();
if (type.equals("cheese")) {
pizza = new CheesePizza(nYIngredientFactory);
pizza.setName("Ney York Style Cheese Pizza");
} else if (type.equals("clam")) {
pizza = new ClamPizza(nYIngredientFactory);
pizza.setName("New York Style Clam Pizza");
}
return pizza;
}
}
createPizza를 추상 메소드로 설정하여 지역에 맞게 pizza를 설정한다.
'공부 > 디자인 패턴' 카테고리의 다른 글
| 6. Command Pattern (Head First Design Patterns) (0) | 2024.10.25 |
|---|---|
| 5. Singleton Pattern (Head First Design Patterns) (0) | 2024.10.22 |
| 3. Decorator Pattern (Head First Design Patterns) (0) | 2024.10.20 |
| 2. Observer Pattern (Head First Design Patterns) (0) | 2024.10.20 |
| 1. Strategy Pattern (Head First Design Patterns) (0) | 2024.10.20 |