In a course I'm taking, a PizzaStore
that uses a SimplePizzaFactory
class which handles concrete pizza instantiation, described as follows:
In the course, an intro to the factory method pattern is described by introducing the need to provide the PizzaStore with extra levels of specificity and the ability to provide the same types of Pizzas (Viggie, Cheese, etc..) but in a NY-Style and in a Chicago-Style, so we have a new set of subclasses (NYStyleViggiePizza, NYStyleCheesePizza, .. ChicagoStyleViggiePizza, ChicagoStyleCheesePizza, .. )
The solution introduced by the instructor was to use the factory method pattern as follows:
(UML)
Code re-written in python:
# Pizzas Subclasses are defined elsewhere
from abc import ABC, abstractmethod
class PizzaStore(ABC):
@abstractmethod
def create_pizza(self):
pass
def order_pizza(self,type_of_pizza):
type_of_pizza = type_of_pizza.lower()
pizza = self.create_pizza(type_of_pizza)
pizza.prepare()
pizza.bake()
pizza.box()
return pizza
class NYPizzaStore(PizzaStore):
def create_pizza(self, type_of_pizza):
if type_of_pizza == "cheese":
pizza = NYStyleCheesePizza()
elif type_of_pizza == "pepperoni":
pizza = NYStylePepperoniPizza()
elif type_of_pizza == "clam":
pizza = NYStyleClamPizza()
elif type_of_pizza == "viggie":
pizza = NYStyleViggiePizza()
else:
raise Exception("You need to specify a type of NY pizza.")
return pizza
class ChicagoPizzaStore(PizzaStore):
def create_pizza(self,type_of_pizza):
if type_of_pizza == "cheese":
pizza = ChicagoStyleCheesePizza()
elif type_of_pizza == "pepperoni":
pizza = ChicagoStylePepperoniPizza()
elif type_of_pizza == "clam":
pizza = ChicagoStyleClamPizza()
elif type_of_pizza == "viggie":
pizza = ChicagoStyleViggiePizza()
else:
raise Exception("You need to specify a type of NY pizza.")
return pizza
# ===== Driver Code =====
# NY store
ny_pizza_store = NYPizzaStore()
ny_pizza_store.order_pizza("Cheese")
ny_pizza_store.order_pizza("Pepperoni")
print()
# Chicago store
chicago_pizza_store = ChicagoPizzaStore()
chicago_pizza_store.order_pizza("Cheese")
chicago_pizza_store.order_pizza("Pepperoni")
I tried the following design before jumping in to the factory method, where I kept the PizzaStore as it is and replaced the SimpleFactoryPizza
with two new classes: NYPizzaFactory
and ChicagoPizzaFactory
Code re-written in python:
class NYPizzaFactory():
def create_pizza(self,type_of_pizza):
if type_of_pizza == "cheese":
pizza = NYStyleCheesePizza()
elif type_of_pizza == "pepperoni":
pizza = NYStylePepperoniPizza()
elif type_of_pizza == "clam":
pizza = NYStyleClamPizza()
elif type_of_pizza == "viggie":
pizza = NYStyleViggiePizza()
else:
raise Exception("You need to specify a type of NY pizza.")
return pizza
class ChicagoPizzaFactory():
def create_pizza(self,type_of_pizza):
if type_of_pizza == "cheese":
pizza = ChicagoStyleCheesePizza()
elif type_of_pizza == "pepperoni":
pizza = ChicagoStylePepperoniPizza()
elif type_of_pizza == "clam":
pizza = ChicagoStyleClamPizza()
elif type_of_pizza == "viggie":
pizza = ChicagoStyleViggiePizza()
else:
raise Exception("You need to specify a type of NY pizza.")
return pizza
# PizzaStore is the same as before
class PizzaStore:
def __init__(self, pizza_factory_obj):
self.pizza_factory_obj = pizza_factory_obj
def order_pizza(self,type_of_pizza):
type_of_pizza = type_of_pizza.lower()
pizza = self.pizza_factory_obj.create_pizza(type_of_pizza)
pizza.prepare()
pizza.bake()
pizza.box()
return pizza
# ===== Driver Code ======
# NY Store
ny_pizza_factory = NYPizzaFactory()
ny_pizza_store = PizzaStore(ny_pizza_factory)
ny_pizza_store.order_pizza("Cheese")
print()
ny_pizza_store.order_pizza("Pepperoni")
print()
# Chicago Store
chicago_pizza_factory = ChicagoPizzaFactory()
chicago_pizza_store = PizzaStore(chicago_pizza_factory)
chicago_pizza_store.order_pizza("Cheese")
print()
chicago_pizza_store.order_pizza("Pepperoni")
I understand that a Factory Method lets a class defer instantiation to its subclasses, where these subclasses will include the implementation of that "factory method".
Question 1:
- By definition, Is my solution not considered a factory pattern? What are the differences and downsides to the approach I tried compared to the factory method represented?
Question 2:
The factory method structure is generalized by the following UML: (from the course material)
In the "Design Patterns: Elements of Reusable Object-Oriented Software" book, the Factory method pattern's structure is described via this UML:
- The arrow between the factory and the product represents "aggregation" from the course material, while the UML diagram in the book represents "Dependency" (I think), Which one represents the correct relationship and why?