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

하루키·2024년 7월 26일

DesignPattern

목록 보기
5/7
post-thumbnail

📖 팩토리 메서드 패턴(Factory Method Pattern) 이란?

팩토리 메서드 패턴(Factory Method Pattern)은 객체 생성의 책임을 메서드로 분리하고,
이를 추상클래스나 인터페이스에 정의하여 구체적인 구현 클래스에서
객체 생성의 세부사항을 결정하도록 하는 디자인 패턴


⚠ SimplePizzaFactory 의 문제점

  • SimplePizzaFactory는 현재 하나의 종류만 만들 수 있음 → 지역 별 스타일 반영 불가

NY Style, CHI Style, CAL Style 각각의 CheesePizza 를 만들 수 없음!

  • 지역별로 다른 스타일의 피자를 만들어야 함
    구상클래스에 의존하는 코드를 만들면 확장성에 불리함
  • 피자 종류 별 팩토리 사용
    NYPizzaFactory nyFactory = new NYPizzaFactory();
    PizzaStore nyStore = new PizzaStore(nyFactory);
    nyStore.order("Veggie");
    
    ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
    PizzaStore nyStore = new PizzaStore(ChicagoFactory);
    chicagoStore.order("Veggie");
    ⚠ 구상 클래스에 의존하는 코드가 됨

💡 해결책


📌 피자 가게 프레임 워크

  • SimpleFactory로 분리한 createPizza() 를 다시 PizzaStore로 가지고 옴,
    but 피자 종류 결정(객체 생성의 책임)은 PizzaStore에서 하지 않음
    → 추상 메서드로 정의 (팩토리 메서드에 해당)
  • PizzaStore를 상속 받는 구상 클래스에서 createPizza() 를 구현
    → 객체 생성을 책임지는 factoryMethod를 구현한다


💬 UML 및 동작 원리

✔ 팩토리 메서드 UML

  • Product : 팩토리 메서드가 생성할 객체의 인터페이스나 추상 클래스. 기존의 Pizza 추상클래스에 해당
  • ConcreteProduct : 추상 제품을 구현하는 구체적인 클래스. 기존의 Cheese, Veggie Pizza 등 해당
  • Creator : 팩토리 메서드를 정의하는 추상 클래스. 기존의 PizzaStore에 해당.
    🚩 객체 생성을 책임지는 factoryMethod() 를 추상 메서드로 선언
    → 해당 메서드를 ConcreteCreator 에서 오버라이드 하여 정의한다!!
  • ConcreteCreator : 추상팩토리를 상속하고, 팩토리메서드를 구현하여 객체생성을 책임지는 클래스


✔ 피자 가게 : 팩토리 메서드 설계 UML

  • PizzaStore 에서 createPizza() 를 사용하여 원하는 스타일의 피자를 생성해서 주문에 대응
    → Creator 에 해당
  • NYPizzaStore ,ChicagoPizzaStore : 어떤 스타일의 피자를 생성할지 결정
    → ConcreteCreator 에 해당
  • Pizza : Product에 해당
  • NYStyleCheesePizza, ChicagoStyleCheesePizza … : ConcreteProduct에 해당


📃 코드

PizzaStore 코드

public abstract class PizzaStore {
    
        protected abstract Pizza createPizza(String type);
        // 팩토리 메서드. 서브클래스에서 객체 생성을 책임져야 함
    
        public Pizza orderPizza(String type) {
    
            Pizza pizza = createPizza(type);
            // 어떤 피자가 만들어지는 지 알 수 없다.
            // 즉, 실제로 생성되는 구상 객체가 무엇인지 알 수 없게 한다.
            // 신기하게도 이 상태로 컴파일이 가능하다!
            
            System.out.println("---Making a " + pizza.getName() + "---");
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
            pizza.deliver();
            return pizza;
        }
    }

NYPizzaStore, CHIPizzaStore 코드

public class NYPizzaStore extends PizzaStore {
    
        @Override
        protected Pizza createPizza(String type) {
            if (type.equals("cheese")) {
                return new NYStyleCheesePizza();
            } else if (type.equals("veggie")) {
                return new NYStyleVeggiePizza();
            } else {
                return null;
            }
        }
    }
    ```
    
    ```java
    public class CHIPizzaStore extends PizzaStore {
    
        @Override
        protected Pizza createPizza(String type) {
            if (type.equals("cheese")) {
                return new CHIStyleCheesePizza();
            } else if (type.equals("veggie")) {
                return new CHIStyleVeggiePizza();
            } else {
                return null;
            }
        }
    }
    

🔔 새로운 스타일의 피자를 추가하려면 PizzaStore를 상속받는 새로운 클래스와 해당 클래스에서 createPizza 메서드를 구현하면 된다. ex) ItalyPizzaStore
→ 클라이언트 코드는 변경할 필요 없이 새로운 피자 스타일을 사용할 수 있게 된다!

📌 이러한 방식으로 새로운 피자 스타일을 쉽게 추가할 수 있으며, 기존 코드의 수정 없이도 확장성을 유지할 수 있다


TestDriver 코드

public class TestDriver {
    
        public static void main(String[] args) {
            PizzaStore nyStore = new NYPizzaStore();
            PizzaStore chiStore = new CHIPizzaStore();
    
            Pizza pizza = nyStore.orderPizza("cheese");
            System.out.println("Ethan 주문 " + pizza.getName() + "\n");
    
            pizza = chiStore.orderPizza("cheese");
            System.out.println("Joel 주문 " + pizza.getName() + "\n");
    
            pizza = nyStore.orderPizza("veggie");
            System.out.println("Ethan 주문 " + pizza.getName() + "\n");
    
            pizza = chiStore.orderPizza("veggie");
            System.out.println("Joel 주문 " + pizza.getName() + "\n");
    
        }
    }
profile
코딩 못하는 개발자(진)

0개의 댓글