팩토리 메소드 패턴
객체의 생성을 서브클래스에 캡슐화한다.
어떤 객체를 생성할지를 런타임에 결정할 수 있다.
팩토리 메소드는 일반적으로 하나의 객체를 생성한다.
[특징]
상속을 통해 서브클래스에서 팩토리 메소드(일반적으로 createXXX로 명명됨)를 오버라이딩해서 객체의 생성부를 구현
팩토리 메소드 클래스에서 생성할 타깃의 추상 클래스와 상속받은 클래스들
Pizza 추상 클래스를 상속해서 실제 피자 클래스(치즈피자, 페페로니피자 ...)를 만든다.
public abstract class Pizza {
String name;
String dough;
String sauce;
void prepare() {
System.out.println("Prepare " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cut the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
public class ChicagoStyleClamPizza extends Pizza {
public ChicagoStyleClamPizza() {
name = "Chicago Style Clam Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
... 생략
팩토리 추상 클래스
createXxxxx(createPizza)가 팩토리 메소드 패턴의 핵심
참고로 orderPizza 메소드는 템플릿 메소드 패턴임
public abstract class PizzaStore {
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
팩토리 메소드 구성 클래스
팩토리 메소드 추상 클래스를 상속받아 실제 객체(인스턴스)를 만들어 주는 팩토리 메소드 로직을 구현한다.
실제 생성할 클래스가 명시적으로 담겨 있어서 새로운 클래스(피자)가 추가되면 팩토리 메소드도 함께 수정을 해야 한다.
public class ChicagoPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new ChicagoStyleCheesePizza();
} else if (item.equals("veggie")) {
return new ChicagoStyleVeggiePizza();
} else if (item.equals("clam")) {
return new ChicagoStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new ChicagoStylePepperoniPizza();
} else return null;
}
}
추상 팩토리 패턴
서로 연관되거나 의존적인 객체들의 집합을 생성해야 할 때 사용한다.
추상체에 객체의 집합을 생성하기 위한 정의를 위치시키고, 하위의 구현체에서 세부적인 집합 생성 과정을 구현한다.
객체들의 조합을 인터페이스로 제공하고, 서브 클래스에서 객체를 생성한다.
생성 대상 클래스들의 추상체(인터페이스 또는 추상 클래스) 및 실제 클래스
본 예제에서는 피자에 사용되는 재료들을 종류별로 정의했다.
피자 종류별로 재료로 사용되는 도우, 소스, 치즈, 야채 등이 정해져 있는(집합) 관계에 있어서 추상 팩토리 예제로 적합하다.
public interface Dough {
public String toString();
}
public interface Sauce {
public String toString();
}
public interface Cheese {
public String toString();
}
public interface Veggies {
public String toString();
}
// Doughs
public class ThickCrustDough implements Dough {
public String toString() {
return "ThickCrust style extra thick crust dough";
}
}
...
// Sources
public class MarinaraSauce implements Sauce {
public String toString() {
return "Marinara Sauce";
}
}
// Cheeses
public class ParmesanCheese implements Cheese {
public String toString() {
return "Shredded Parmesan";
}
}
//Veggies
public class Mushroom implements Veggies {
public String toString() {
return "Mushrooms";
}
}
public class Onion implements Veggies {
public String toString() {
return "Onion";
}
}
추상 팩토리 인터페이스 - 피자 구성품
집합을 구성할 클래스들(도우, 소스, 치즈, 야채들) 각각의 생성자 메소드 정의되어 있다.
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
}
추상 팩토리 구상 클래스
시카고 피자 재료 팩토리 클래스에서는 두꺼운 크러스트 도우, 플럼토마토, 모짜렐라치즈, 야채들(블랙 올리브, 시금치, 가치)를 준비한다.
public class ChicagoPizzaIngredientFactory
implements PizzaIngredientFactory
{
public Dough createDough() {
return new ThickCrustDough();
}
public Sauce createSauce() {
return new PlumTomatoSauce();
}
public Cheese createCheese() {
return new MozzarellaCheese();
}
public Veggies[] createVeggies() {
Veggies veggies[] = { new BlackOlives(),
new Spinach(),
new Eggplant() };
return veggies;
}
}
추상 팩토리의 사용
아래 예에서는 추상 팩토리(피자 재료 준비 팩토리 클래스)의 인스턴스를 만들어서 각각의 피자(치즈 피자, 아채 피자...)에 생성자 파라미터로 넣어주는 방식으로 일반적인 피자(치즈피자, 야채피자)에 재료를 바꿔 시카고스타일의 피자(시카고스타일 치즈피자, 시카고스타일 야채피자)를 만들 수 있도록 했다.
public abstract class PizzaStore {
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
//팩토리 메소드 패턴
// 내부에서 추상 팩토리 패턴을 사용하고 있다.
public class ChicagoPizzaStore extends PizzaStore {
protected Pizza createPizza(String item) {
Pizza pizza = null;
//추상 팩토리 패턴
PizzaIngredientFactory ingredientFactory =
new ChicagoPizzaIngredientFactory();
//팩토리 메소드 패턴
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("Chicago Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("Chicago Style Veggie Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("Chicago Style Clam Pizza");
}
return pizza;
}
}
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
//추상 팩토리 패턴에서 실제 객체의 집합이 만들어지는 시점
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
veggies = ingredientFactory.createVeggies();
}
}
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
abstract void prepare();
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
}
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore chicagoStore = new ChicagoPizzaStore();
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("pepperoni");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
'프로그래밍 > OOP_Pattern_TDD' 카테고리의 다른 글
디자인 패턴 범주별 분류 (0) | 2022.07.28 |
---|---|
디자인패턴 카탈로그 (0) | 2022.07.28 |
OOP - SOLID 원칙 5.의존관계 역전 원칙, Dependency Inversion Principle (0) | 2022.07.26 |
OOP - SOLID 원칙 4.인터페이스 분리 원칙(ISP, Interface Segregation Principle) (0) | 2022.07.26 |
OOP - SOLID 원칙 3.리스코프 치환 원칙(LSP, Liskov Substitution Principle) (0) | 2022.07.22 |