디자인 패턴 - 팩토리 패턴

본 게시글은 '헤드퍼스트-디자인 패턴 (개정판)'을 기준으로 작성된 글입니다.

 

문제점 찾아보기

Duck duck;
if (picnic) {
	duck = new MallardDuck();
}
else if (hunting){
	duck = new DecoyDuck();
}
else if (inBathTub) {
	duck = new RubberDuck();
}

다음 코드에서의 문제점은, 각 조건에 따라 다른 Duck이 생성이 된다. 

만약 새로운 Duck을 추가하기 위해 확장한다면, 어떤 것을 추가하고 삭제해야할 지 코드를 다시 확인해야 한다.

 

결론

Concrete Class(구상 클래스)를 많이 사용하면, 새로운 구상 클래스가 추가될 때마다 코드를 고쳐야하므로 많은 문제가 생길 수 있다.

결국 변화에 닫혀 있는 코드가 된다 (OCP 위반) →(해결) 바뀔 수 있는 부분을 찾아내서 바뀌지 않는 부분하고 분리시켜야 한다.

 

코드의 reuse를 위한 목적으로 콘크리트 클래스를 쓰지 마라.

 

구상클래스 : new 키워드를 사용하여 인스턴스를 만드는 클래스


피자 만들기

Pizza orderPizza(String type) {
       Pizza pizza;
       if(type.equals("cheese")) pizza = new CheesePizza();
       else if(type.equals("greek")) pizza = new GreekPizza();
       else if(type.equals("pepperoni")) pizza = new PepperoniPizza();       
       pizza.prepare();
       pizza.bake();
       pizza.cut();
       pizza.box();
       return pizza;
 }

상황 : 피자 가게를 운영하고 있고 피자 가게 클래스를 만든다.

변화하는 부분 : if문 부분을 캡슐화 한다.

 

캡슐화한 코드

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

피자를 생성하는 부분을, 정의한다. 

 

코드 수정하기

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

PizzaStore에 SimplePizzaFactory의 레퍼런스를 저장한다. 

생성자에 팩토리 객체가 전달이 된다.

주문 형식만 지정해주면, 피자 객체를 만들 수 있다. 

 

new 연산자를 사용하는 대신 create 메소드를 사용했다. 

 


새로운 상황

각 지역마다의 특색을 살려 지역별 다양한 스타일의 피자를 만들어야 하는 상황.

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);

각 분점을 위한 서브클래스를 만들어두고 피자의 각 스타일은 서브 클래스에서 결정하도록 하였다.

 

피자 객체 인스턴스를 만드는 일은 PizzaStore의 서브클래스의 createPizza() 메소드에서 처리한다.

 

public class NYPizzaStore extends PizzaStore{
	@Override
	public Pizza createPizza(String type){
		Pizza pizza = null;
		if(type.equals("cheese")) pizza = new NYStyleCheesePizza();
		if(type.equals("peper")) pizza = new NYStylePepperoniPizza();
		if(type.equals("clam")) pizza = new NYStyleClamPizza();
		if(type.equals("veggie")) pizza = new NYStyleVeggiePizza();
		return pizza;
	}
 }
public abstract class Pizza{
	String name;
	String dough;
	String sauce;
	ArrayList<String> toppings = new ArrayList<>();
	
	public void prepare(){
		System.out.println("Preparing : "+name);
		System.out.println("Tossing dough...");
		System.out.println("Adding source");
		System.out.println("Adding toppings");
		for (String topping : toppings) {
			System.out.println("\ttopping : "+topping);
		}
	}
	
	public void bake(){
		System.out.println("Bake for 25 minutes at 350");
	}
	
	public void cut(){
		System.out.println("Cutting the pizza into diagonal slices");
	}
	
	public void box(){
		System.out.println("Place pizza in official PizzaStore box");
	}
	
	public String getname(){
		return this.name;
	}
	
 }
```java
public class ChicagoStyleCheesePizza extends Pizza{
	public ChicagoStyleCheesePizza() {
		this.name = "Chicago Style CheesePizza";
		this.dough = "Extra Thick Crust Dough";
		this.sauce = "Plum Tomato Sauce";
		this.toppings.add("Shredded mozzarella Cheese");
	}
	@Override
	public void cut() {
		System.out.println("Cutting the pizza into square slices");
	}
 }
```

팩토리 메소드 패턴

모든 팩토리 패턴에서는 객체 생성을 캡슐화한다. 팩토리 메소드 패턴에서는 어떤 서브클래스를 만들지 결정하게 함으로써 캡슐화를 한다.

 

팩토리 패턴을 통해 DIP를 지킨다

이유

 

[기존의 의존성]

PizzaStore -> NYStyleCheesePizza

PizzaStore -> ChicagoStypeCheesePizza

PizzaStore -> NYStyleVeggiePizza

 

 

[팩토리 패턴 적용 후 의존성]

PizzaStore -> Pizza

Pizza <- NYStyleCheesePizza

Pizza <- ChicagoStyleCheesePizza

Pizza <- NYStyleVeggiePizza

'디자인패턴' 카테고리의 다른 글

[디자인 패턴] - 데코레이터 패턴  (1) 2023.09.01
[디자인 패턴] - 옵저버 패턴  (0) 2023.08.31
[디자인패턴] - 전략 패턴  (0) 2023.08.30