ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 팩토리 패턴
    개발/flutter 2020. 9. 14. 17:54

    팩토리 패턴

     

    팩토리 패턴은 기본적으로 객체를 생성하는 패턴이다.

    기본적으로 객체를 생성할떄 이렇게 생성한다.

    Pizza orderPizza(String type){
      Pizza pizza;
        
      if(type=='cheese'){
        pizza = CheesePizza();
      }else if(type=='pepperoni'){
        pizza = PepperoniPizza();
      }
        
      pizza.bake();
      pizza.cut();
        
      return pizza;
    }

    위와같이 피자 타입에따라 피자를 생성할때 이런 식으로 생성한다.

    하지만 예로 새로운 피자종류가 생기거나 치즈피자 판매를 중단하려면

    코드를 수정해야한다.

     

    저렇게 타입별로 피자를 생성하는 부분은 계속 바뀔수있으며 그럴 때마다 코드를 수정해야 하기 때문에

    바뀌는부분은 캡슐화를 하는게 좋다.

    그래서 팩토리 패턴을 사용한다.

    abstract class Pizza{
      prepare();
      cut();
      bake();
      box();
    }
    
    
    
    class CheesePizza implements Pizza{
      @override
      bake() {
       print('bake CheesePizza');
      }
    
      @override
      box() {
       print('box CheesePizza');
      }
    
      @override
      cut() {
        print('cut CheesePizza');
      }
    
      @override
      prepare() {
       print('prepare CheesePizza');
      }
    
    }
    
    class PepperoniPizza implements Pizza{
      @override
      bake() {
        print('bake PepperoniPizza');
      }
    
      @override
      box() {
       print('box PepperoniPizza');
      }
    
      @override
      cut() {
        print('cut PepperoniPizza');
      }
    
      @override
      prepare() {
        print('prepare PepperoniPizza');
      }
    
    }

    우선 피자를 추상클래스로 정의하고 메소드를 정의해주고

    피자 종류에따라 서브클래스를 만들어준다.

     

    이제 피자 가게에서 피자를 만들때 팩토리를 사용해 타입을 넘겨준뒤 피자를 생성한다.

    class PizzaStore{
      PizzaStore({this.factory});
      PizzaFactory factory;
    
    
      Pizza orderPizza(String type){
        Pizza pizza;
    
        pizza = factory.createPizza(type);
    
        pizza.bake();
        pizza.cut();
    
        return pizza;
      }
    }
    
    
    class PizzaFactory{
      createPizza(String type){
        if(type=='cheese'){
          return CheesePizza();
        }else if(type=='pepperoni'){
          return PepperoniPizza();
        }
      }
    }

    팩토리에서는 타입을받아 알맞은 피자를 리턴해주고

    피자가게에서 orderPizza 에서 피자를 리턴받은뒤 굽고 잘라서 피자를 리턴해준다.

     

     

     

    이번엔 조금 더 복잡한 피자구조를 만들어보자

    치즈,페페로니 피자뿐만아니라 지역별로 나누려한다. 

    뉴욕 지점과 시카고 지점을 낼것이다. 그러므로 뉴욕치즈/뉴욕페페로니/시카고치즈/시카고페페로니 피자가있다.

     

    피자부터 정의해주고

    abstract class Pizza{
      prepare();
      cut();
      bake();
      box();
    }
    
    
    
    class NYStyleCheesePizza implements Pizza{
      @override
      bake() {
       print('bake NYStyleCheesePizza');
      }
    
      @override
      box() {
       print('box NYStyleCheesePizza');
      }
    
      @override
      cut() {
        print('cut NYStyleCheesePizza');
      }
    
      @override
      prepare() {
       print('prepare NYStyleCheesePizza');
      }
    
    }
    
    class NYStylePepperoniPizza implements Pizza{
      @override
      bake() {
       print('bake NYStylePepperoniPizza');
      }
    
      @override
      box() {
       print('box NYStylePepperoniPizza');
      }
    
      @override
      cut() {
        print('cut NYStylePepperoniPizza');
      }
    
      @override
      prepare() {
       print('prepare NYStylePepperoniPizza');
      }
    
    }
    
    class ChicagoStyleCheesePizza implements Pizza{
      @override
      bake() {
        print('bake ChicagoStyleCheesePizza');
      }
    
      @override
      box() {
       print('box ChicagoStyleCheesePizza');
      }
    
      @override
      cut() {
        print('cut ChicagoStyleCheesePizza');
      }
    
      @override
      prepare() {
        print('prepare ChicagoStyleCheesePizza');
      }
    
    }
    class ChicagoStylePepperoniPizza implements Pizza{
      @override
      bake() {
        print('bake ChicagoStylePepperoniPizza');
      }
    
      @override
      box() {
       print('box ChicagoStylePepperoniPizza');
      }
    
      @override
      cut() {
        print('cut ChicagoStylePepperoniPizza');
      }
    
      @override
      prepare() {
        print('prepare ChicagoStylePepperoniPizza');
      }
    
    }

     

    이번에는 피자가게 클래스를 추상클래스로 구현하고 뉴욕가게와 시카고 가게에서 상속 받을것이다.

    abstract class PizzaStore{
      Pizza pizza;
      orderPizza(String type){ 
    
        pizza = createPizza(type);
        
        pizza.prepare();
        pizza.cut();
        pizza.bake();
        pizza.box();    
    
        return pizza;
      }
    
      createPizza(String item);
    }
    
    
    class NYPizzaStore extends PizzaStore{
      @override
      createPizza(String item) {
        if(item=='cheese'){
          return NYStyleCheesePizza();
        }else if(item=='pepperoni'){
          return NYStylePepperoniPizza();
        }
      }
    
    }
    
    class ChicagoPizzaStore extends PizzaStore{
      @override
      createPizza(String item) {
        if(item=='cheese'){
          return ChicagoStyleCheesePizza();
        }else if(item=='pepperoni'){
          return ChicagoStylePepperoniPizza();
        }
      }
    
    }
    
    

     

    이후 뉴욕에서 치즈피자를

    시카고에서 페페로니 피자를 이런식으로 주문할수있다.

     final ny = NYPizzaStore();
     final chicago = ChicagoPizzaStore();
    
     ny.orderPizza('cheese');
     chicago.orderPizza('pepperoni');

     

     

    객체를 생성하는 코드를 슈퍼클래스(추상클래스) 에서 분리하였음을 볼수있다.

    슈퍼클래스에서는 어디서 어떤 피자를만드는지 모른다.

    이와같이 팩토리 메소드 클래스(PizzaStore)에서는 객체를 생성하기 위한 인터페이스를 정의하고

    어떤 클래스의 인스턴스를(뉴욕치즈피자) 만들지 서브 클래스(뉴욕피자 Store) 에서 정의한다.

    즉 서브클래스에 인스턴스만드는것을 맡기는목적이다.

     

    왜?

    만약 팩토리 패턴을 사용하지 않고 같은 기능을 만든다면 다음과 같을것이다.

    Pizza orderPizza(String location , String type){
      Pizza pizza;
        
      if(location=='NY'){
        if(type=='cheese'){
          pizza = NYCheesePizza();
        }else if(type=='pepperoni'){
          pizza = NYPepperoniPizza();
        }
      }else if(location=='Chicago'){
        if(type=='cheese'){
          pizza = ChicagoCheesePizza();
        }else if(type=='pepperoni'){
          pizza = ChicagoPepperoniPizza();
        }
      }
     
        
      pizza.bake();
      pizza.cut();
        
      return pizza;
    }

    그닥 나쁘지는 않다.

    물론 location 의종류와 type 의 종류가 계속 증가할수록 코드는 복잡해질것이며

    피자의 종류가 어떻게 바뀌냐에따라 orderPizza의 구현도 바뀔수도있다.

    이를 orderPizza가 Pizza class(피자종류) 에 의존적이다 라고한다.

     

     

    댓글

Designed by Tistory.