팩토리 패턴 정리

임종혁·2024년 12월 4일

1.문제: 구상 클래스의 의존성

코드를 유연하게 작성하려고 Duck duck = new MallardDuck();처럼 작성해도,
결국 MallardDuck이라는 구상 클래스에 의존하게 됨.

예를 들어, if-else로 조건마다 새로운 Duck 객체를 생성하면 코드 수정과 확장이 어려워지고 유지보수가 복잡해짐.

2. Pizza 사례를 통한 문제 이해

Pizza 클래스와 이를 생성하는 Order 클래스 존재.
Pizza 종류가 다양해지면, Order 클래스에서 if-else로 구상 클래스를 선택해야 함.

if (type.equals("cheese")) {
    pizza = new CheesePizza();
} else if (type.equals("pepperoni")) {
    pizza = new PepperoniPizza();
}

문제: 피자 종류가 늘어나면 Order 클래스 코드를 수정해야 하므로 유연하지 않음.

3. 해결 방법: 변하는 부분 분리

SimplePizzaFactory 도입

class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new CheesePizza();
        } else if (type.equals("pepperoni")) {
            return new PepperoniPizza();
        }
    }
}
class Order {
    SimplePizzaFactory factory;
    public Order(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza = factory.createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

Order 클래스 수정
SimplePizzaFactory를 생성자 주입으로 받아서 사용

4. 팩토리 메소드 패턴 적용

다양한 스타일의 피자를 만들기 위해 Order를 추상 클래스로 만들고 팩토리 메소드 createPizza를 추상화.

abstract class Order {
    public Pizza orderPizza(String type) {
        Pizza pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }

    abstract Pizza createPizza(String type);
}

뉴욕 스타일과 시카고 스타일의 Order 클래스를 각각 구현.

class NYPizzaOrder extends Order {
    @Override
    Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new NYStyleCheesePizza();
        }
        return null;
    }
}
class ChicagoOrder extends Order {
    @Override
    Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new ChicagoStyleCheesePizza();
        }
        return null;
    }
}

5. 팩토리 메소드 패턴의 특징

템플릿 메소드 패턴과의 차이점

템플릿 메소드: 알고리즘 구조를 정의하고 세부 구현을 서브클래스에 맡김.
팩토리 메소드: 객체 생성에 초점, 어떤 클래스의 인스턴스를 만들지는 서브클래스가 결정.
장점

6. 의존성 역전 원칙(DIP)

추상화에 의존하고 구상 클래스에 의존하지 않도록 설계.
예를 들어, Order는 Pizza 추상 클래스에 의존하며, 구상 클래스는 팩토리를 통해 관리.

  • 구상 클래스의 참조를 변수에 저장하지 말 것.
  • 구상 클래스를 기반으로 새로운 클래스를 만들지 말 것.

7. 결론

팩토리 메소드 패턴은 객체 생성의 책임을 서브클래스에 위임함으로써 코드의 유연성과 유지보수성을 향상시킨다.
의존성 역전 원칙을 적용하면 고수준 모듈과 저수준 모듈 모두 추상화에 의존하게 되어 설계가 견고해진다.

0개의 댓글