[생성패턴] 2. 팩토리 패턴 (추상 팩토리, 팩토리 메서드)

Carrot.___.·2023년 11월 16일

디자인패턴

목록 보기
2/6

팩토리 패턴의 종류

  • 추상 팩토리 패턴(Abstract Pattern) : 서로 연관되거나 의존적인 객체들의 조합을 만드는 인터페이스를 제공하는 패턴
  • 팩토리 메서드 패턴(Factory Method Pattern) : 객체를 생성하는 인터페이스를 정의하고, 객체 생성은 서브 클래스(팩토리)로 위임하는 패턴

추상 팩토리 패턴 (Abstract Factory Pattern)


구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생상하는 인터페이스를 제공합니다. 구상 클래스는 서브클래스에서 만듭니다.

장점

  • 구체적인 클래스를 분리한다. (어떤 제품군이 생산되는지 알 필요가 없음)
  • 제품군을 쉽게 대체할 수 있다.

단점

  • 새로운 종류의 제품을 제공하기 어렵다.

추상 팩토리 예제 코드

팩토리용 인터페이스

public interface PizzaIngredientFactory {
	Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
    Veggies[] createVeggies();
	Pepperoni createPepperoni();
    public Clams createClam();
}

구현 클래스

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
	public Dough createDough() {
    	return new ThinCrustDough();
    }
    
    public Sauce createSauce() {
    	return new MarinaraSauce();
    }
    
    public Cheese createCheese() {
    	return new ReggianoCheese();
    }
    
    public Veggie[] createVeggies() {
    	return new Veggies[] { new Garlic(), new Onion(), new Mushroom() };
    }
    
    public Pepperoni createPepperoni() {
    	return new SlicedPepperoni();
    }
    
    public Clams createClam() {
    	return new FreshClams();
    }
}

활용 클래스

public class CheesePizza extends Pizza {
	PizzaIngredientFactory ingredientFactory;
    
    public CheesePizza(PizzaIngredientFactory ingredientFactory) {
    	this.ingredientFactory = ingredientFactory;
    }
    
    void prepare() {
    	dough = ingreedientFactory.createDough();
        sauce = ingredientFactory.createSource();
        cheese = ingredientFactory.createCheese();
    }
}

위 코드들을 보면, PizzaIngredientFactory라는 제품군으로 피자를 생성하는 예제 코드입니다.
만약, 뉴욕 피자 재료(NYPizzaIngredientFactory)가 아닌 시카고 피자 재료로 피자를 만들어야 한다면, PizzaIngredientFactory를 구현한 ChicagoPizzaIngredientFactory를 구현하여 제공하면 됩니다.

위에서 설명한 장단점을 다시 한번 살펴보면

  • 장점1 : 구체적인 클래스를 분리한다 -> 어떤 제품군이 생산되는지 CheesePizza 클래스는 알지 못합니다. 하지만, NYPizzaIngredientFactory라는 구체적인 클래스로 분리하여, 유연한 객체 생성이 가능합니다.
  • 장점2 : 제품군을 쉽게 대체할 수 있다. -> 만약, 제품군을 다른 방식으로 생성한다면, PizzaIngredientFactory를 구현한 다른 클래스를 제공하면 됩니다.
  • 단점1 : 새로운 종류의 제품을 제공하기 어렵다. -> 새로운 제품군을 제공하려면, 무조건 인터페이스를 구현한 클래스가 존재해야 합니다. 따라서, 인터페이스를 구현한 새로운 제품군을 생성해야 합니다.

팩토리 메소드 패턴 (Factory Method Pattern)


객체를 생성할 때 필요한 인터페이스를 만듭니다. 팩토리 메소드 패턴을 사용하면 클래스 인스턴스 만드는 일을 서브 클래스에세 맡기게 됩니다.

장점

  • 생성에 쓰이는 공통 로직을 추상화할 수 있다

단점

  • 클라이언트가 추상 클래스를 반드시 상속해야 한다.

팩토리 메소드 예제 코드

추상 팩토리용 추상 클래스

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

추상 팩토리 구현 클래스

public class NYPizzaStore extends PizzaStore {
	
    Pizza createPizza(String item) {
    	if(item.equals("cheese") {
        	return NYCheesePizza();
        } else if(item.equals("veggie")) {
        	return new NYVeggiePizza();
        } else if(item.equals("calm") {
        	return new NYCalmPizza();
        } 
        return null;        
    }
}

위에서 설명한 장단점을 다시 한번 살펴보면

  • 장점 : 생성에 쓰이는 공통 로직을 추상화할 수 있다 -> 위 코드에서 중간에 createPizza() 메소드만 구현하면 되고, 생성되는 로직은 공통으로 처리할 수 있습니다.
  • 단점 : 클라이언트가 추상 클래스를 반드시 상속해야 한다. -> 이는, 클래스간의 결합도를 높일 수 있습니다. 만약, 중간에 추상적인 로직이 추가된다면, 해당 클래스를 상속한 모든 클래스에서 코드 수정이 이루어져야 합니다.



결론 (추상 팩토리 패턴 vs 팩토리 메소드 패턴)

  1. 목적
  • 추상 팩토리: 여러 제품군을 생성하며, 이 제품들 간의 일관성을 유지하는 데 중점을 둡니다. 클라이언트가 어떤 구체적인 클래스를 생성할지에 대한 결정을 내리는 것이 아니라, 여러 제품군에 대한 팩토리를 제공하여 일련의 관련된 제품들을 생성할 수 있게 합니다.
  • 팩토리 메소드: 단일 제품을 생성하며, 하위 클래스가 어떤 구체적인 클래스의 인스턴스를 생성할지 결정하도록 합니다.
  1. 클래스 구조
  • 추상 팩토리: 제품군을 생성하기 위한 여러 팩토리 메소드를 제공하는 인터페이스를 정의합니다. 구체적인 팩토리는 이 인터페이스를 구현하여 여러 제품을 생성합니다.
  • 팩토리 메소드: 제품을 생성하기 위한 인터페이스를 정의하고, 이를 구현하는 하위 클래스에서 실제 생성 로직을 구현합니다.
  1. 확장성
  • 추상 팩토리: 새로운 제품군을 추가하기가 상대적으로 쉽습니다. 그러나 새로운 제품을 추가하려면 모든 팩토리 클래스를 수정해야 할 수 있습니다.
  • 팩토리 메소드: 새로운 제품을 추가하기가 상대적으로 쉽지만, 새로운 제품군을 추가하기는 어려울 수 있습니다.
  1. 응용 분야
  • 추상 팩토리: 일반적으로 제품군이나 테마와 같이 여러 관련된 객체를 함께 생성해야 할 때 사용됩니다.
  • 팩토리 메소드: 특정 제품을 생성하는 방법이 하위 클래스에 따라 달라져야 하는 경우에 사용됩니다.

0개의 댓글