심플 팩토리(SimpleFactory)

하루키·2024년 7월 2일

DesignPattern

목록 보기
4/7
post-thumbnail

📖 심플 팩토리(Simple Factory)란?

SimpleFactory는 종종 디자인 패턴으로 오해되기도 하지만, 실제로는 공식적인 디자인 패턴은 아니다!
SimpleFactory는 특정 문제를 해결하기 위한 간단한 기법이나 관용구로 간주됨.


📌 SimpleFactory 가 패턴으로 사용되지 않는 이유

  • 정형화된 패턴의 부재
  • 유연성과 확장성 부족
    SimpleFactory는 객체 생성의 단순화를 목표로 하지만, 확장성과 유연성 측면에서 한계가 있다. 새로운 클래스가 추가되거나 기존 클래스가 수정될 때마다 SimpleFactory 코드를 변경해야 함
  • 의존성 주입과의 비교
    SimpleFactory는 종종 클라이언트 코드가 특정 팩토리 구현에 의존하게 하므로 결합도를 높일 수 있다.
    ex) 클라이언트 코드가 SimplePizzaFactory를 직접 생성하여 PizzaStore에 전달

⚠ new 의 문제점

  • 구상 클래스를 바탕으로 코딩 → 코드 수정 가능성 ↑, 유연성 ↓
  • 코드에 구상 클래스를 많이 사용하면, 새로운 구상 클래스가 추가될 때 마다 코드를 고쳐야 하기 때문에 문제 발생 가능성 有
    → 변화(확장)에 대해 닫혀 있는 코드
  • 바뀔 수 있는 부분을 찾아내서, 바뀌지 않는 부분하고 분리 시켜야 함 (캡슐화)
  • new 문제점 코드 예시
    Duck duck;
    
    if(picnic) {
    	duck = new MallardDuck();
    } else if (hunting) {
    	duck = new DecoyDuck();
    } else if (inBathTub) {
    	duck = new RubberDuck();
    }

⚠ PizzaStore 의 문제점

  • 상속을 이용한 구현
  • Pizza에 변화가 생겨도, Pizza의 코드가 바뀌는게 아니라 PizzaStore의 코드가 변경
    ex) 기존 피자 삭제, 새로운 피자 생산 추가 etc
  • PizzaStore 클래스는 피자를 주문하고 찍어내기만 해야 함. 어떤 피자를 생성할지는 서브클래스에서 결정 (단일 책임 원리)
  • PizzaStore UML
  • PizzaStore 코드 문제점
    public class PizzaStore {
    
        public Pizza orderPizza(String type) {
            Pizza pizza = null;
    
            if (type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (type.equals("greek")) {
                // 더 이상 그릭피자를 생산하지 않는다면?
                pizza = new GreekPizza();
            } else if (type.equals("pepperoni")) {
                pizza = new PepperoniPizza();
            }
    
            // clam pizza와 veggie pizza를 생산해야 한다면?
            // 구현에 대해 프로그래밍하여 코드 변경에 대해 닫혀 있지 않음.
            // pizza가 제대로 생성되지 않으면?
            // -> Null pointer dereference (널 포인터 역참조)
            if (pizza != null) {
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            }
    
            return pizza;
        }
    } 

디자인 원칙

OCP(Open-Closed Principle) : 확장에는 열려 있고, 수정에는 닫혀 있는 코드


💬 UML 및 동작 원리

✔ Simple Factory UML

  • SimplePizzaFactory 클래스를 만들어서, 객체 생성을 위임
    → 객체 생성 부분을 캡슐화

Simple Factory는 패턴이 아님! → 일종의 관용구

  • 정형화된 패턴의 부재

  • 유연성과 확장성 부족

    SimpleFactory는 객체 생성의 단순화를 목표로 하지만, 확장성과 유연성 측면에서 한계가 있다. 새로운 클래스가 추가되거나 기존 클래스가 수정될 때마다 SimpleFactory 코드를 변경해야 함

  • 의존성 주입과의 비교

    SimpleFactory는 종종 클라이언트 코드가 특정 팩토리 구현에 의존하게 하므로 결합도를 높일 수 있다.
    → 클라이언트 코드가 SimplePizzaFactory를 직접 생성하여 PizzaStore에 전달


📃 코드

PizzaStore 코드

    public class PizzaStore {
    
        private SimplePizzaFactory factory; // 먼저 생성됨 (피자스토어 생성자 보다)
    
        public PizzaStore(SimplePizzaFactory factory) {
            this.factory = factory; // 연관에 의한 초기화
        }
    
        public Pizza orderPizza(String type) {
            Pizza pizza;
    
            pizza = factory.createPizza(type);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
    
            return pizza;
    
        }
    }
  • 기존 코드의 orderPizza 에서 어떤 피자를 만들지 결정하는 메서드를, 클래스로 분리 하여 위임
    SimpleFactory 에 해당!
  • SimplePizzaFactory 클래스는 피자 객체 생성에 대한 책임을 가진다
  • SimplePizzaFactory를 연관으로 가지고, 해당 팩토리가 피자의 타입을 결정함
    → PizzaStore은 prepare, bake, cut, box 만 하면 됨! (SOLID) 원칙
  • 클라이언트 코드(PizzaStore)는 피자 생성에 대한 세부 사항을 몰라도 된다.

SimplePizzaFactory 코드

     public class SimplePizzaFactory {
    
        public Pizza createPizza(String type) {
            Pizza pizza = null;
    
            if (type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if (type.equals("veggie")) {
                pizza = new VeggiePizza();
            } else if (type.equals("pepperoni")) {
                pizza = new PepperoniPizza();
            } else if (type.equals("clam")) {
                pizza = new ClamPizza();
            }
            return pizza;
        }
    	// 
    }
  • 기존 PizzaStore의 객체 생성 로직을 분리! → 캡슐화

💡 새로운 피자 종류를 추가할 때 SimplePizzaFactory 클래스만 수정하면 됨!

profile
코딩 못하는 개발자(진)

0개의 댓글