객체지향 및 기반 언어/디자인 패턴

[Design Pattern] Chapter 04 팩토리 패턴

박지환 2022. 10. 1. 18:45

팩토리 메소드 패턴의 정의

팩토리 메소드 패턴(Factory Method Pattern)에서는 객체를 생성할 때 필요한 인터페이스를 만든다. 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정한다. 팩토리 메소드 패턴을 사용하면 클래스 인스턴스 만드는 일을 서브클래스에게 맡기게 된다.

팩토리 메소드 패턴 UML

 

추상 클래스의 추상 팩토리 메소드를 서브클래스가 팩토리 메소드를 구현해서 객체를 생산한다.

팩토리 메소드 패턴 예제 코드

public abstract class Pizza {

    String name;

    Dough dough;
    Sauce sauce;
    Veggies veggies[];
    Cheese cheese;
    Pepperoni pepperoni;
    Clams clams;

    public abstract void prepare();

    public void bake() {
        System.out.println("175도에서 25분 간 굽기");
    }

    public void cut() {
        System.out.println("피자를 사선으로 자르기");
    }

    public void box() {
        System.out.println("상자에 피자 담기");
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
public class PepperoniPizza extends Pizza {

    PizzaIngredientFactory ingredientFactory;

    public PepperoniPizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("준비 중: " + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}

Pizza 추상 클래스는 피자를 만들기 위한 공통적인 속성들과 메소드들을 구현하고 있으며, 일부(prepare())는 Pizza를 상속한 PepperoniPizza 구상 클래스와 같은 서브 클래스가 각자의 알고리즘에 따라 구현하고 있다.

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 {

    @Override
    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();

        if (item.equals(("cheese"))) {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("뉴욕 스타일 치즈 피자");
        } else if (item.equals("pepperoni")) {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("뉴욕 스타일 페퍼로니 피자");
        }

        return pizza;
    }
}

PizzaStore 추상 클래스는 Pizza 객체를 만들기 위한 일련의 과정을 구현해 놓았으며, 이 추상 클래스를 구현한 NYPizzaStore와 같은 구상 클래스들은 일부 과정(createPizza())을 오버라이드하여 Pizza 객체를 만들기 위한 각자의 알고리즘을 구현한다.

public class PizzaTestDrive {

    public static void main(String[] args) {
        PizzaStore nyStore = new NYPizzaStore();
        PizzaStore chicagoStore = new ChicagoPizzaStore();

        Pizza pizza = nyStore.orderPizza("cheese");
        System.out.println("에단이 주문한 " + pizza.getName() + "\n");

        pizza = chicagoStore.orderPizza("cheese");
        System.out.println("조엘이 주문한 " + pizza.getName() + "\n");
    }
}

Pizza 객체 생성을 NYPizzaStore에 요청하면, NYPizzzaStore는 구현한 일련의 절차에 따라 객체를 생성하여 반환해준다. 다른 피자 가게(ChicaPizzaStore)에 요청할 경우 다른 생성 알고리즘에 따라 객체를 생성해준다.

의존성 뒤집기 원칙

디자인 원칙 6: 의존성 뒤집기 원칙(Dependency Inversion Principle) 추상화된 것에 의존하게 만들고 구상 클래스에 의존하지 않게 만든다.

의존성 뒤집기 원칙을 지키는 방법

  • 변수에 구상 클래스의 레퍼런스를 저장하지 말자.
  • 구상 클래스에서 유도된 클래스를 만들지 말자.
  • 베이스 클래스에 이미 구현되어 있는 메소드를 오버라이드하지 말자.

추상 팩토리 패턴의 정의

추상 팩토리 패턴(Abstract Factory Pattern)은 구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공한다. 구상 클래스는 서브클래스에서 만든다.

추상 팩토리 패턴 UML

 

 

추상 팩토리 인터페이스를 구현한 구상 팩토리가 관련성 있는 여러 종류의 객체들을 일관된 방식으로 생산한다.

추상 팩토리 패턴 예제 코드

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies veggies[] = { new Garlic(), new Onion() };
        return veggies;
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Clams createClam() {
        return new FreshClams();
    }
}

NYPizzaIngredientFactory는 Pizza 객체 생성을 위해 필요한 재료(Ingredients) 각각의 제품군 중에서, 해당 Pizza 객체에 맞는 재료의 제품(예를 들어 Cheese 제품군 중에서는 ReggianoCheese)을 객체를 생성하여 반환한다.

핵심 정리

  • 팩토리를 쓰면 객체 생성을 캡슐화할 수 있음.
  • 간단한 팩토리는 엄밀하게 말해서 디자인 패턴은 아니지만, 클라이언트와 구상 클래스를 분리하는 간단한 기법으로 활용할 수 있음.
  • 팩토리 메소드 패턴은 상속을 활용함. 객체 생성을 서브클래스에게 맡김. 서브클래스는 팩토리 메소드를 구현해서 객체를 생산함.
  • 추상 팩토리 패턴은 객체 구성을 활용함. 팩토리 인터페이스에서 선언한 메소드에서 객체 생성이 구현됨.
  • 모든 팩토리 패턴은 애플리케이션의 구상 클래스 의존성을 줄여줌으로써 느슨한 결합을 도와줌.
  • 팩토리 메소드 패턴은 특정 클래스에서 인스턴스를 만드는 일을 서브클래스에게 넘김
  • 추상 팩티로 패턴은 구상 클래스에 직접 의존하지 않고도 서로 관련된 객체로 이루어진 제품군을 만드는 용도로 쓰임.
  • 의존성 뒤집기 원칙을 따르면 구상 형식 의존을 피하고 추상화를 지향할 수 있음.
  • 팩토리는 구상 클래스가 아닌 추상 클래스와 인터페이스에 맞춰서 코딩할 수 있게 해 주는 강력한 기법임.

 

GitHub Code Reference: https://github.com/Krapi0314/Design_Patterns

 

GitHub - Krapi0314/Design_Patterns: Java Implementation of GoF's Design Patterns

Java Implementation of GoF's Design Patterns. Contribute to Krapi0314/Design_Patterns development by creating an account on GitHub.

github.com

Reference: http://www.yes24.com/Product/Goods/108192370

 

헤드 퍼스트 디자인 패턴 - YES24

유지관리가 편리한 객체지향 소프트웨어 만들기!“『헤드 퍼스트 디자인 패턴(개정판)』 한 권이면 충분하다.이유 1. 흥미로운 이야기와 재치 넘치는 구성이 담긴 〈헤드 퍼스트〉 시리즈! 하나

www.yes24.com