팩토리 메서드 패턴

ynkim·2024년 10월 31일
0

문제

Pizza orderPizza(String type) {
  Pizze pizza;
  
  if (type.equals("cheese")) {
  	pizza = new CheesePizza();
  } else if (type.equals("pepperoni")) {
  	pizza = new PepperoniPizza();
  }
  
  pizza.bake();
}

피자가게에서 피자 주문을 처리하는 로직이다. 여기서 신메뉴가 추가된다고 했을 때, type에 따라 피자를 생성하는 if-else 구문이 변경되어야 한다.

간단한 팩토리

팩토리: 객체 생성을 처리하는 클래스

# 팩토리
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();
        }
    }
}
# 클라이언트
public class PizzaStore {
	SimplePizzaFactory factory;
    
    public PizzaStore(SimplePizzaFactory factory) {
    	this.factory = factory;
    }
    
	public Pizza orderPizza(String type) {
    	Pizza pizza = null;
        
        pizza = factory.createPizza(type);
        
        pizza.bake();
    }
}

orderPizza()에서 직접 구상 클래스의 인스턴스를 만들지않고 팩토리를 사용하도록 수정했다.
만약 PizzaStore가 아니라 다른 곳에서도 인스턴스 생성 코드가 필요할 때 인스턴스 생성 부분이 바뀌더라도 팩토리 클래스만 수정하면 된다.
이와 같이 간단한 팩토리의 경우 createPizza를 정적 메서드로 선언하여 정적 팩토리로 만들어 사용하는 경우가 많다.

팩토리 메서드 패턴

지역별 피자가게가 생긴다고 가정해서 간단한 팩토리를 적용시킨 코드는 다음과 같다.

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStroe.orderPizza("Cheese");

ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.orderPizza("Cheese");

이 경우에 피자 인스턴스는 팩토리를 통해 생성하지만 피자를 만드는 과정은 제각각 달라질 수 있다. 따라서 PizzaStore와 피자 제작 코드를 묶는 작업이 필요하다.

public abstract class PizzaStore {
	public Pizza orderPizza(String type) {
    	Pizza pizza;
        
        pizza = createPizza(type);
        
        pizza.bake();
        
        return pizza;
    }
    
    abstract Pizza createPizza(String type);
}

각 지점은 PizzaStore의 서브클래스를 만들고 createPizza 메서드를 오버라이드한다.

public class NYStylePizzaStore extends PizzaStore {    
    public Pizza createPizza(String type) {
    	if (type.equals("cheese")) {
        	return new NYStyleCheesePizza();
        } else if (type.equals("pepperoni")) {
        	return new NYStylePepperoniPizza();
        } else {
        	return null;
        }
    }
}
public class ChicagoStylePizzaStore extends PizzaStroe {    
    public Pizza createPizza(String type) {
    	if (type.equals("cheese")) {
        	return new ChicagoStyleCheesePizza();
        } else if (type.equals("pepperoni")) {
        	return new ChicagoStylePepperoniPizza();
        } else {
        	return null;
        }
    }
}
  • 팩터리 메서드를 추상 메서드로 선언해서 서브클래스가 객체 생성을 책임지도록 한다.
  • 팩토리 메서드는 특정 객체(Product)를 리턴하며 그 객체는 보통 슈퍼클래스가 정의한 메서드 내에서 쓰인다.
  • 팩터리 메서드는 클라이언트(orderPizza())에서 실제로 생성되는 구상 객체가 무엇인지 알 수 없게 한다. 어떤 객체가 생성될 것인지는 어떤 서브클래스를 선택하느냐에 따라 결정된다. (객체 생성을 캡슐화)

생성자(Creator) - 제품(Product) 클래스

추상 생산자 클래스(PizzaStore)

  • 서브클래스에서 제품을 생산하려고 구현하는 팩토리 메서드(createPizza)를 정의
    구상 생산자 클래스(NYPizzaStore, ChicagoPizzaStore)
  • 팩토리 메서드를 구현
    제품 클래스
  • 팩토리가 생산하는 제품(Pizza)

팩토리 메서드 패턴

  • 객체를 생성할 때 필요한 인터페이스를 만들고 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정
  • Creator에는 제품을 사용하는 메서드가 구현되어 있지만 제품을 만들어 주는 팩토리 메서드는 서브클래스에서 구현한다.

0개의 댓글