As i wish

[Design pattern] Abstact Factory pattern (추상 팩토리 패턴) 본문

Design Pattern

[Design pattern] Abstact Factory pattern (추상 팩토리 패턴)

어면태 2019. 2. 17. 19:43

안녕하세요

오늘은 추상 팩토리 패턴에 대하여 공부해 보겠습니다.


일단 전에 포스팅 했던 팩토리 메소드 패턴과 너무 헷갈려서 엄청난 혼동이 생겼었는데요.

결국 해결 하고 포스팅을 쓰게 되서 상당히 다행입니다.

팩토리 패턴은 정말 헷갈리는것 같아요.


먼저 정의 부터 확인하겠습니다.

추상 팩토리 패턴

- 추상 팩토리 패턴에서는 인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고도 생성할 수 있습니다.

다양한 구성 요소 별로 객체의 집합을 생성할때 유용합니다.


네 무슨말인지 정말 헷갈리는데요

제가 이해한 바로는 정말 추상적으로 클래스를 만들고 그 안에 추상 메소드를 만든 뒤 서브 클래스들이 각각 추상 메소드를 구성하는 형태라고 생각하면 쉽습니다.

정말 말 그대로 추상 클래스인거죠, 그런데 팩토리 패턴 (팩토리 메소드 패턴 - 서브 클래스에서 어떤 인스턴스를 만들지 결정) 에 맞게 각각에 메소드를 결정한다면 그게 추상 팩토리 패턴이라고 생각이 드네요



위 처럼 각각의 추상클래스가 가지고 있는 추상 메소드를 서브 클래스들의 의하여 생성되는 거죠

그럼 우리의 피자 스토어를 확장 시켜 보겠습니다.




즉, PizzaIngredientFactory를 추상화 시키고 각각의 메소드 역시 추상화 되어 있죠(Sauce, Pepperoni)

각각의 메소드 역시 각각의 객체들로 이루어져 있는것을 추상 팩토리 패턴이라고 정의 할 수 있겠네요.


위 UML 디자인은 '팩토리 패턴' 에 대한 UML 디자인인데요. 위의 Pizzastore는 PizzaIngredientFactory를 받아서 Pizza를 만들게 되는 것이죠.

Pizzastore는 팩토리 패턴, 그 안에 PizzaIngredientFactory는 추상 팩토리 패턴을 사용하고 있고, 밑에서는 이 둘을 합쳐서 코드를 만들어 보겠습니다.


<요 글이 조금 더 이해하기 쉬워서 퍼왔어요~>

팩토리 메서드 패턴

: 조건에 따른 객체 생성을 팩토리 클래스로 위임하여, 팩토리 클래스에서 객체를 생성하는 패턴


추상 팩토리 패턴

: 서로 관련이 있는 객체들을 통째로 묶어서 팩토리 클래스로 만들고, 이들 팩토리를 조건에 따라 생성하도록 다시 팩토리를 만들어서 객체를 생성하는 패턴


추상 팩토리 패턴은 어떻게 보면, 팩토리 메서드 패턴을 좀 더 캡슐화한 방식이라고 볼 수 있습니다.

출처: https://victorydntmd.tistory.com/300 [victolee]


마지막으로 코드로 확인하시죠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# -*- coding: utf-8 -*-
# Absctract Factory Pattern
 
import abc
 
class Pizzastore:
  __metaclass__ = abc.ABCMeta
 
  def orderPizza(self, type):
    pizza = self.createPizza(type)
 
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
 
    return pizza
 
  @abc.abstractmethod
  def createPizza(self, type):
    pass
 
class ChicagoPizzaStore(Pizzastore):
  def createPizza(self, type):
    pizza = None
    ingredient_factory = ChicagoPizzaIngredientFactory()
 
    if type == 'CHEESE':
      pizza = CheesePizza(ingredient_factory)
    elif type == 'PEPPERONI':
      pizza = PepperoniPizza(ingredient_factory)
    else:
      pizza = NormalPizza(ingredient_factory)
 
    return pizza
 
class NYPizzaStore(Pizzastore):
  def createPizza(self, type):
    pizza = None
    ingredient_factory = NYPizzaIngredientFactory()
 
    if type == 'CHEESE':
      pizza = CheesePizza(ingredient_factory)
    elif type == 'PEPPERONI':
      pizza = PepperoniPizza(ingredient_factory)
    else:
      pizza = NormalPizza(ingredient_factory)
 
    return pizza
 
class PizzaIngredientFactory:
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractmethod
  def createSauce(self):
    pass
 
  @abc.abstractmethod
  def createCheese(self):
    pass
 
class ChicagoPizzaIngredientFactory(PizzaIngredientFactory):
  def getName(self):
    return 'Chicago style'
 
  def createPepperoni(self):
    return ChicagoPepperoni()
 
  def createSauce(self):
    return ChicagoSauce()
 
  def createCheese(self):
    return ChicagoCheese()
 
 
class NYPizzaIngredientFactory(PizzaIngredientFactory):
  def getName(self):
    return 'NY style'
 
  def createPepperoni(self):
    return NYPepperoni()
 
  def createSauce(self):
    return NYSauce()
 
  def createCheese(self):
    return NYCheese()
 
class Pepperoni:
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractmethod
  def getName(self):
    pass
 
class NYPepperoni(Pepperoni):
  def getName(self):
    return 'NY Pepperoni'
 
class ChicagoPepperoni(Pepperoni):
  def getName(self):
    return 'Chicago Pepperoni'
 
class Sauce:
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractmethod
  def getName(self):
    pass
 
class NYSauce(Sauce):
  def getName(self):
    return 'NY Sauce'
 
class ChicagoSauce(Sauce):
  def getName(self):
    return 'Chicago Sauce'
 
class Cheese:
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractmethod
  def getName(self):
    pass
 
class NYCheese(Cheese):
  def getName(self):
    return 'NY Cheese'
 
class ChicagoCheese(Cheese):
  def getName(self):
    return 'Chicago Cheese'
 
class Pizza:
  __metaclass__ = abc.ABCMeta
 
  @abc.abstractmethod
  def prepare(self):
    pass
 
  def bake(self):
    print('Bake %s' %self.name)
 
  def cut(self):
    print('Cut %s' %self.name)
 
  def box(self):
    print('Boxing %s' %self.name)
 
class NormalPizza(Pizza):
  def __init__(self, ingredient_factory):
    self.factory = ingredient_factory
    self.name = 'Pizza'
    self.dough = 'None'
    self.sauce = 'None'
 
  def prepare(self):
    self.name = self.factory.getName() + ' ' + self.name
 
    print('Prepare %s' %self.name)
    print('Dough %s' %self.dough)
    print('Sauce %s' %self.sauce)
 
class CheesePizza(Pizza):
  def __init__(self, ingredient_factory):
    self.factory = ingredient_factory
    self.name = 'Cheese Pizza'
    self.dough = 'None'
    self.sauce = 'None'
 
  def prepare(self):
    self.name = self.factory.getName() + ' ' + self.name
    self.dough = self.factory.createCheese()
    self.sauce = self.factory.createSauce()
 
    print('Prepare %s' %self.name)
    print('Dough %s' %self.dough.getName())
    print('Sauce %s' %self.sauce.getName())
 
 
class PepperoniPizza(Pizza):
  def __init__(self, ingredient_factory):
    self.factory = ingredient_factory
    self.name = 'Pepperoni Pizza'
    self.dough = 'None'
    self.sauce = 'None'
 
  def prepare(self):
    self.name = self.factory.getName() + ' ' + self.name
    self.dough = self.factory.createPepperoni()
    self.sauce = self.factory.createSauce()
 
    print('Prepare %s' %self.name)
    print('Dough %s' %self.dough.getName())
    print('Sauce %s' %self.sauce.getName())
 
 
chicagoStore = ChicagoPizzaStore()
nyStore = NYPizzaStore()
 
nyStore.orderPizza('CHEESE')
print("###############")
chicagoStore.orderPizza('PEPPERONI')
print("############")
chicagoStore.orderPizza('CHEESE')
 
cs




지난번 팩토리 메소드 패턴과 최대한 비슷하게 결과가 나오도록 코드를 구성하였습니다.


Comments