본문 바로가기

Design-Pattern

빵처럼 객체를 구워내자! 팩토리 패턴(factory pattern)

1. 팩토리 패턴(factory pattern) 이란?

팩토리(factory)를 번역해 보면 공장이란 뜻을 가지고 있습니다.

팩토리 패턴을 간단하게 설명하면 제품을 공장에서 생산하는것처럼 팩토리 패턴은 객체를 서브 클래스에서 생성하는 패턴이다.

 

사실 위에서 말한 팩토리 패턴은 패턴의 마치 공장을 연상하기 위해 쉽게 표현한 것에 가깝고 조금 더 정확하게 팩토리 패턴을 설명하면 

객체를 생성 하기 위해 필요한 인터페이스를 만들고, 해당하는 인터페이스를 구현한 클래스에서 어떤 객체를 만들지 결정하는 패턴이다.

 

이러한 팩토리 패턴을 UML로 표현하면 다음과 같다.

팩토리 패턴 UML

팩토리 패턴은 크게 2가지 종류로 사용이 가능한데 각각 팩토리 메소드 패턴, 추상 팩토리 패턴이 있습니다.

2. 팩토리 패턴(factory pattern) 특징?

2-1. 팩토리 메서드 패턴

팩토리 메소드 패턴은 객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스 클래스를 만드는지 서브클래스에서 결정하게 만드는 패턴입니다.

여기서 가장 중요한 건 서브 클래스입니다.

부모의 추상 클래스는 인터페이스에만 의존하고 실제로 어떤 구현 클래스를 호출할지는 서브 클래스에서 구현하기 때문에

기존 Factory코드의 수정 없이 진행이 가능합니다.

 

2-2. 추상 팩토리 패턴

추상 팩토리 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고 생성할 수 있는 팩토리 패턴이라고 설명이 가능한데 조금 더 쉽게 풀어보면

 서로 관련 있는 객체를 묶어서 하나의 팩토리 클래스로 만들고 이들 하위의 구현체에서 집합을 생성하는 것입니다.

기존 팩토리 메서드 패턴에서 조금 더 캡슐화를 강화시킨 형태라고 보입니다. + 특정 상황에서 종속성의 제거

 

팩토리 패턴을 써야 하는 경우

필요한 객체의 생성을 위임하는 특징 덕분에 팩토리 패턴은 다음가 같은 상황에서 쓰기 좋습니다.

 

 1. 객체 생성의 책임을 서브 클래스에 위임시키고 해당 정보를 캡슐화시키자 할 때

 2. 객체 색선의 책임을 서브 클래스로 넘기고자 할 때(기존 코드의 수정 X)

 3. 생성할 타입을 예측할 수 없을 때

 

이러한 특징 덕분에 팩토리 패턴을 사용하면

기존 코드를 수정하지 않고 새로운 인스턴스를 생성하 용이하며

코드의 구조가 단순해진다는

명확한 장점이 있지만

 

클래스가 많아진다단점도 존재합니다

3. 팩토리 패턴(factory pattern) 구현

팩토리 패턴을 간단하게 구현하면 다음과 같습니다.

CheesePizza

public class CheesePizza extends Pizza {
	public CheesePizza() {
		name = "Cheese Pizza";
		dough = "Regular Crust";
		sauce = "Marinara Pizza Sauce";
		toppings.add("Fresh Mozzarella");
		toppings.add("Parmesan");
	}
}

ClamPizza

public class ClamPizza extends Pizza {
	public ClamPizza() {
		name = "Clam Pizza";
		dough = "Thin crust";
		sauce = "White garlic sauce";
		toppings.add("Clams");
		toppings.add("Grated parmesan cheese");
	}
}

PepperoniPizza

public class PepperoniPizza extends Pizza {
	public PepperoniPizza() {
		name = "Pepperoni Pizza";
		dough = "Crust";
		sauce = "Marinara sauce";
		toppings.add("Sliced Pepperoni");
		toppings.add("Sliced Onion");
		toppings.add("Grated parmesan cheese");
	}
}

Pizza

abstract public class Pizza {
	String name;
	String dough;
	String sauce;
	List<String> toppings = new ArrayList<String>();
	public String getName() { return name; }
	public void prepare() { System.out.println("Preparing " + name); }
	public void bake() { System.out.println("Baking " + name); }
	public void cut() { System.out.println("Cutting " + name); }
	public void box() { System.out.println("Boxing " + 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();
	}
}

PizzaStore

public class PizzaStore {
	SimplePizzaFactory factory; 
	public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; }
	public Pizza orderPizza(String type) {
		Pizza pizza; 
		pizza = factory.createPizza(type);
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}

PizzaTestDriver

public class PizzaTestDrive {
	public static void main(String[] args) {
		SimplePizzaFactory factory = new SimplePizzaFactory();
		PizzaStore store = new PizzaStore(factory);
		Pizza pizza = store.orderPizza("cheese");
		System.out.println("We ordered a " + pizza.getName() + "\n");
		System.out.println(pizza);
		pizza = store.orderPizza("veggie");
		System.out.println("We ordered a " + pizza.getName() + "\n");
		System.out.println(pizza);
	}
}

SimplePizzaFactory

public class SimplePizzaFactory {
	public Pizza createPizza(String type) {
		Pizza pizza = null;
		if (type.equals("cheese")) { pizza = new CheesePizza(); } 
        else if (type.equals("pepperoni")) { pizza = new PepperoniPizza(); } 
        else if (type.equals("clam")) { pizza = new ClamPizza(); }
        else if (type.equals("veggie")) { pizza = new VeggiePizza(); }
		return pizza;
	}
}

VeggiePizza

public class VeggiePizza extends Pizza {
	public VeggiePizza() {
		name = "Veggie Pizza";
		dough = "Crust";
		sauce = "Marinara sauce";
		toppings.add("Shredded mozzarella");
		toppings.add("Grated parmesan");
		toppings.add("Diced onion");
		toppings.add("Sliced mushrooms");
		toppings.add("Sliced red pepper");
		toppings.add("Sliced black olives");
	}
}