[flutter] Factory Pattern(팩토리 패턴)

popolarburr·2023년 9월 27일
0
post-thumbnail


이론



우선 팩토리 패턴을 왜 쓰는지를 알고 기본을 잡아보자

(코드예제)

factory Movie.fromJson(Map<String, dynamic> json) {

	adult: json["adult"],
    backdropPath: json["backdrop_path"] ?? '',
    genreIds: List<int>.from(json["genre ids"]
    
    ...
    ...

}

명칭에 답이 있다. 팩토리와 패턴.
팩토리는 공장, 패턴은 어떠한 문제를 이미 검증된 솔루션(해결책)이 있어 규칙대로 만들면 문제를 해결 할 수 있는 것.


그렇다면 ' 어떠한 문제를 이미 검증된 솔루션의 규칙대로 문제를 해결 할 수 있는 공장' 정도로 이해할 수 있겠다.


현실을 예로 들어보면,

소비자가 A라는 상품을 사기 위해서는 Factory 공장에서 일정한 패턴을 통해 찍어내서 상품을 만들어 판매한다.
이러한 패턴 속에서 소비자가 원하는 원료를 가지고 A상품에 들어가는 원료를 조금 바꿔 B라는 상품을 만들어도 무방하다.
즉, 소비자(client)가 원하는 모델이나 상품을 알맞게 만들어 주는 일정규격이라고 생각하면 된다.

다시 코드 예제로 돌아오면,
Movie에도 다양한 형태의 Movie 객체가 있을 수 있다. 파라미터별로 달라지고, 내부 형태도 다를 수 있다. 하지만 이러한 사실은 소비자(client)는 전혀 모른다. 그렇기 때문에 소비자가 입력을 하면 입력값에 맞게끔 원하는 값을 도출해내는 것이 Factory Pattern이라고 보면 된다.

다시 코드를 가져오면,

factory Movie.fromJson(Map<String, dynamic> json) {

	adult: json["adult"],
    backdropPath: json["backdrop_path"] ?? '',
    genreIds: List<int>.from(json["genre ids"]
    
    ...
    ...

}

이 코드에서 보면 현재는 Map에 adult, backdropPath, genreIds를 Key로 갖고있다.

그러나 value쪽(특히 backdropPath)을 보게되면

backdropPath: json["backdrop_path"] ?? '',

이러한 모습을 띄고 있는 것을 볼 수 있다.

이게 사용자의 요구에 맞춘건데, 공장(Factory)에는 backdropPath라는 것이 있는데, 이게 사용자가 보내주는 것에 따라 유동적으로 값이 변경될 수 있다는 의미다.

즉, 사용자가 A라는 상품을 사기 위해서는 공장에 adult, genreIds, backdropPath와 같은 것들이 필요했지만, B라는 상품을 사기 위해서는 공장에 adult, genreIds는 필요하지만 backdropPath는 불필요할 수 있다는 것이다. -> 필요한 아이템들만 사용

이렇게 하면 장점
1) 싱글톤 패턴이라해서, static을 사용한 효과를 얻을 수있고, 정적으로 사용할 수 있다. = 객체를 생성하지 않고도 사용할 수 있다.

2) 설계도면이 요구사항에 바뀌어도, 클라이언트는 모델생성에 관여하지 않기 때문에 소스 수정을 팩토리 패턴을 사용한 모델에서만 수정할 수 있다는 장점이 있다.



실습



실제 코드 예제 (피자가게에서 피자를 주문하고 그 가격을 출력하는 예제)

void main() {
  var userSelectedPizza = PizzaType.HamMushroom;
  Pizza pizza;
  
  switch(userSelectedPizza) {
    case PizzaType.HamMushroom:
      pizza = HamAndMushroomPizza();
      break;
      
     case PizzaType.Deluxe:
      pizza = DeluxePizza();
      break;

     case PizzaType.Seafood:
      pizza = SeafoodPizza();
      break;
  }
  print(pizza.getPrice()); // 출력 : 10.5
  
}

enum PizzaType { HamMushroom, Deluxe, Seafood}

abstract class Pizza{ // 추상클래스 
  double getPrice(); 
}

class HamAndMushroomPizza implements Pizza {
  double price = 10.5;
  
  
  double getPrice() {
    return price;
  }
}

class DeluxePizza implements Pizza {  
  double price = 7.5;
  
  
  double getPrice() {
    return price; 
  }
}

class SeafoodPizza implements Pizza {
  double price = 12.5;
  
  
  double getPrice() {
    return price;
  }
}
 

위 코드는 팩토리 메서드를 사용하지 않은 코드이다. 일반적인 코드로, 사용자의 입력값에 맞게 해당하는 클래스 및 메서드가 할당 및 실행되는 것을 볼 수 있다.

아래 코드는 팩토리 메서드를 사용한 코드이다.

void main() {
 Map<String, dynamic> json = {
   "type":PizzaType.Pineapple,
 };
 print(Pizza.pizzaFactory(PizzaType.Pineapple).getPrice());
}

...

abstract class Pizza {
  double getPrize();
  factory Pizza.fromJson(Map<String, dynamic> json) {
    switch(json["type"] as PizzaType) {
      case PizzaType.Pineapple:
        return PineapplePizza();
      case PizzaType.Mushroom:
        return MushroomPizza();
      case PizzaType.Cheese:
        return CheesePizza();
    }
  }
} 

...

굳이 팩토리 패턴을 사용해야 할까? 사실 상관없다.
하지만 클라이언트 부분(위 코드에선 메인함수)에서 참조를 하지 않는다는 점이 있다. 팩토리 패턴을 사용하지 않은 상태에서 한 클래스를 수정한다면 참조하는 모든 클래스에서 오류가 발생할 것이다. 엄청 번거로운 작업이다.

하지만 팩토리패턴에서 수정이 이루어진다면 팩토리 패턴을 사용한 곳에서만 오류가 발생할 것이다.

더 저렴한 코드비용으로 큰 기댓값을 불러올 수 있다는 장점이 있꾸나!








[출처 : 이론편] https://www.youtube.com/watch?v=ZikfiBnFMk8
[출처 : 실습편 ]https://www.youtube.com/watch?v=ICaYCojSPko&t=29s
[출처] https://velog.io/@gou5met/Flutter-%ED%8C%A9%ED%86%A0%EB%A6%AC-%ED%8C%A8%ED%84%B4factory-pattern

profile
차곡차곡

0개의 댓글