.
본문 바로가기
디자인패턴

팩토리 패턴1 (factory pattern)

by 와칸다개발자 2021. 9. 24.

firsthead 책을 공부하고 요약한 것입니다.

 

new는 구상객체다.

 

new 지시자는 구상클래스의 인스턴스를 만드는것. new는 나중에 코드를 수정할 가능성이 높아지며 유연성이 떨어진다.

 

  // 인터페이스를 Animal을 사용하였지만 new 지시자를 이용해 구상클래스 생성
  Animal dog = new Dog();

 

다음과 같이 코드를 짜야할 순간이 있다.

 

  if(dogType === 'Maltese'){
      dog = new Maltese();
  }else if(dogType === 'Pomeranian'){
      dog = new Pomeranian();
  }else if(dogType === 'ShihTzu'){
      dog = new ShihTzu();
  }

이런 코드는 만들어지는 인스턴스 형식은 실행시 주어진 로직에 따라 결정된다.

 

이런 코드는 관리 및 갱신하기가 어려워 지며 사이드 이펙트를 생성한다.

 

new 지시자는 당연히 안 쓸 수 없다. new는 변화에 약하다. 인터페이스에 맞춰서 코드를 짜는것은 소프트웨어에서 일어날 

 

변화를 극복할 수 있다.  다형성 때문에 어떤 클래스든 특정 인터페이스만 구현하면 사용이 유연해지기 때문이다.

 

변화에는 닫혀있고 확장에는 열려있어야 한다.

문제점

 

피자가게를 운영하고 있는 코드를 작성해보자

 

  public orderPizza(type:string): Pizza{
  
      let pizza : Pizza;
      
      if(type === 'cheese'){
          pizza = new CheesePizza();
      }else if(type === 'greek'){
          pizza = new GreekPizza();
      }else if(type === 'pepperoni'){
          pizza = new PepperoniPizza();
      }

      pizza.prepare();
      pizza.bake();
      pizza.cut();
      pizza.box();

      return pizza;
  }

 

만약 여기서 메뉴를 추가하거나 삭제해야 한다면...

 

  else if(type === 'potato'){
      pizza = new PotatoPizza();
  }

 

이렇게 코드를 직접 변경해야합니다. 변경에 열려있으며 피자 종류에 따라 코드를 직접 건드려야 겠네요.

 

디자인 원칙 중 하나는 변경되는 부분을 분리해라 

구상 클래스를 생성하는 저 코드를 분리합시다. 피자를 생성하는 코드를 클래스를 이용해 다음과 같이 작성합니다.

 

  class PizzaFactory{
  
	public createPizza(type:string): Pizza{
    
      let pizza:Pizza;
      
      if(type === 'cheese'){
          pizza = new CheesePizza();
      }else if(type === 'greek'){
          pizza = new GreekPizza();
      }else if(type === 'pepperoni'){
          pizza = new PepperoniPizza();
      }

      return pizza;
  	}
  }

 

단순 객체생성 코드를 다른 클래스에 위임한 것 뿐인데 뭐가 다른걸까요?

 

다른 클라이언트 코드 부분에서 피자팩토리를 많이 사용할 때 유용합니다. 피자 생성 팩토리 클래스를 캡슐화 시켜 

 

놓으면 여기저기 고칠 필요 없이 이 팩토리 클래스 하나만 수정하면 됩니다. 

 

다음은 전체적인 클라이언트 코드부분입니다.

 

  abstract class Pizza{}

  class DefaultPizza extends Pizza{}

  class CheesePizza extends Pizza{}

  class GreekPizza extends Pizza{}

  class PepperoniPizza extends Pizza{}

  class PizzaFactory{
  
      private pizza:Pizza;
      constructor(){
          this.pizza = new DefaultPizza();
      }

      public createPizza(pizzaType: string): Pizza{

          if(pizzaType === 'cheese'){
              this.pizza = new CheesePizza();
          }else if(pizzaType === 'greek'){
              this.pizza = new GreekPizza();
          }else if(pizzaType === 'pepperoni'){
              this.pizza = new PepperoniPizza();
          }

          return this.pizza;
      }
  }

  class PizzaStore{
      private pizzaFactory : PizzaFactory;
      constructor(){
          this.pizzaFactory = new PizzaFactory();
      }

      public orderPizza(pizzaType: string){
          let pizza:Pizza;
          pizza = this.pizzaFactory.createPizza('cheese');

          return pizza;        
      }
  }

 

간단하게 팩토리 패턴에 대해 알아보았지만 아직 문제점은 많습니다. 

 

피자스토어가 너무 잘되어 여러 지점에서 운영을 하고 싶다면 어떻게 작성해야 할까요? 

 

다음에 게시하도록 하겠습니다.

'디자인패턴' 카테고리의 다른 글

퍼사드 패턴(Facade Pattern)  (0) 2022.02.04
전략패턴 (Strategy Pattern )  (0) 2021.09.21
데코레이터 패턴(Decorator Pattern)  (0) 2021.09.21
싱글톤 패턴 (singleton pattern)  (0) 2021.09.16

댓글