객체 생성 부분을 추상화한 패턴으로, 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정한다.
OO 원칙
- 추상화된 것에 의존하게 만들고, 구상 클래스에 의존하지 않게 만든다.
Dependency Inversion Principle(의존성 역전 원칙)
- 변수에 구상클래스의 레퍼런스를 저장하지 않는다.
- 구상클래스에서 유도된 클래스를 만들지 않는다.
- 베이스 클래스에 이미 구현되어 있는 클래스를 오버라이드 하지 않는다.
피자 종류에 따라 객체를 생성하고, 그에 맞게 피자를 만드는 코드
기존 코드
Pizza orderPizza(String type) {
Pizza pizza;
if(type.equals("cheese") {
pizza = new CheesePizza();
} else if(type.equlas("greek") {
pizza = new GreekPizza();
} ....
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
Simple Factory
public class SimplePizzaFactory {
public Pizza createPizza(String type){
Pizza pizza = null;
// 객체 생성 - 인스턴스에 따라 객체 생성
if(type.equals("cheese") {
pizza = new CheesePizza();
} else if(type.equlas("greek") {
pizza = new GreekPizza();
} ....
return pizza;
}
}
Client
public class PizzaStore {
SimplePizzaFactory factory; //팩토리 레퍼런스 저장
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory; // 팩토리 지정
}
public Pizza orderPizza(String type) {
Pizza pizza; // 피자 객체 생성
pizza = factory.createPizza(type); // type에 따라 객체 생성
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
Abstract Factory
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 item); // 추상 클래스로 지정, 지점마다 다름
}
Concrete Factory
public class NYPizzaStore extends PizzaStore { // 상속
/// 팩토리 메서드
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
Product
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList<String> toppings = new ArrayList<String>();
void prepare() {
System.out.println("Prepare " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (String topping : toppings) {
System.out.println(" " + topping);
}
}
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 String toString() {
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings) {
display.append(topping + "\n");
}
return display.toString();
}
}
Concrete Product
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
Test.java
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore(); // Factory 객체 생성 - 다형성
Pizza pizza = nyStore.orderPizza("cheese"); // Product 객체 생성 - Factory에서 생성한 객체를 넘겨준다.
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
}
}
고수준 구성요소인 PizzaStore와 저수준 구성요소인 Pizza 객체들이 모두 추상클래스인 Pizza 의존하게 된다. => 의존성 역전 원칙
** 고수준 구성요소는 다른 저수준 구성요소에 의해 정의되는 행동이 들어있는 구성요소를 뜻한다
ex) PizzaStore의 행동은 Pizza에 의해 결정된다.
구상클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공한다. 구상 클래스는 서브클래스에서 만든다.
Abstract Factory
// 원재료를 생산하는 팩토리 interface
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
Concrete Factory
// 가게마다 원재료를 생산하는 팩토리 생성
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
}
public Sauce createSauce() {
return new MarinaraSauce();
}
public Cheese createCheese() {
return new ReggianoCheese();
}
public Veggies[] createVeggies() {
Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return veggies;
}
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
public Clams createClam() {
return new FreshClams();
}
}
// 원재료 interface
public interface Dough {
public String toString();
}
Abstarct Class
public abstract class PizzaStore {
protected 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;
}
}
Client
public class NYPizzaStore{
protected Pizza createPizza(String item) {
Pizza pizza = null;
// 원재료 팩토리 선언
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
} else if (item.equals("clam")) {
pizza= new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
} else if (item.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
Abstract Product
public abstract class Pizza {
String name;
//원재료들
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
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 String toString() {
StringBuffer result = new StringBuffer();
result.append("---- " + name + " ----\n");
if (dough != null) {
result.append(dough);
result.append("\n");
}
if (sauce != null) {
result.append(sauce);
result.append("\n");
}
if (cheese != null) {
result.append(cheese);
result.append("\n");
}
if (veggies != null) {
for (int i = 0; i < veggies.length; i++) {
result.append(veggies[i]);
if (i < veggies.length-1) {
result.append(", ");
}
}
result.append("\n");
}
if (clam != null) {
result.append(clam);
result.append("\n");
}
if (pepperoni != null) {
result.append(pepperoni);
result.append("\n");
}
return result.toString();
}
}
Concrete Product
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();
}
}
Test.java
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore(); // pizza store 객체 생성
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza + "\n");
pizza = nyStore.orderPizza("pepperoni");
System.out.println("Ethan ordered a " + pizza + "\n");
}
}
팩토리메서드 패턴
추상팩토리 패턴