Factory Method¶
The factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. Defines an interface for creating an instance of an object but lets the class which implements the interface decide which class to instantiate.
Example use cases of Factory Method¶
use case: ordering a pizza from a pizza store¶
Let's say we have a pizza shop and we want to order the pizza. When we order the pizza, the pizza shop will need to do the following functionalities. 1. prepare it 2. bake it 3. cut it 4. box it
In this scenario, we can define classes PizzaStore
, Pizza
. The class PizzaStore
will acts as a client which will talk to the class Pizza
which contains the methods prepare
, bake
, cut
and box
.
Let's dive into the code.
# service
class Pizza:
def prepare(self):
""" prepare the pizza """
def bake(self):
""" bake the pizza """
def cut(self):
""" cut the baked pizza into a required shape """
def box(self):
""" move the pizza into the box """
# client
class PizzaStore:
def order_pizza(self):
""" order and get pizza """
pizza = Pizza()
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
if __name__ == '__main__':
store = PizzaStore()
store.order_pizza()
Above code will work for only one type of pizza. If we have multiple pizza type classes then we need to have a Factory
to decide the class to be used for the client request. If we don't use the Factory
then client needs to handle the logic with the pizza type classes which is not recommended. Let's the see the code without the Factory
pattern.
from abc import ABC, abstractmethod
class Pizza(ABC):
@abstractmethod
def prepare(self):
""" prepare the pizza """
@abstractmethod
def bake(self):
""" bake the pizza """
@abstractmethod
def cut(self):
""" cut the baked pizza into a required shape """
@abstractmethod
def box(self):
""" move the pizza into the box """
class PizzaMixin:
pizza_type = ""
def prepare(self):
""" prepare the pizza """
print(f"prepare {self.pizza_type} pizza")
def bake(self):
""" bake the pizza """
print(f"bake {self.pizza_type} pizza")
def cut(self):
""" cut the baked pizza into a required shape """
print(f"cut {self.pizza_type} pizza")
def box(self):
""" move the pizza into the box """
print(f"box {self.pizza_type} pizza")
class CheesePizza(PizzaMixin, Pizza):
pizza_type = "cheese"
class VegPizza(PizzaMixin, Pizza):
pizza_type = "veg"
# client
class PizzaStore:
def order_pizza(self, pizza_type):
""" order and get pizza """
# logic to decide the pizza class
pizza = None
if(pizza_type == "cheese"):
pizza = CheesePizza()
elif(pizza_type == "veg"):
pizza = VegPizza()
if pizza is None:
raise Exception("Invalid pizza type")
# we can have more types of pizza classes
# end
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
if __name__ == '__main__':
store = PizzaStore()
store.order_pizza("cheese")
In the above code we can see that the client class PizzaStore
need to know the details of the classes CheesePizza
, VegPizza
. If we want to add a new pizza type then we need to modify the client class code. By using the factory pattern we can avoid it. Let's implement the Factory pattern by seperating the pizza type logic
pizza = None
if(pizza_type == "cheese"):
pizza = CheesePizza()
elif(pizza_type == "veg"):
pizza = VegPizza()
Let's create a factory class and move logic.
class PizzaFactory:
def create_pizza(self, pizza_type):
pizza = None
if(pizza_type == "cheese"):
pizza = CheesePizza()
elif(pizza_type == "veg"):
pizza = VegPizza()
if pizza is None:
raise Exception("Invalid pizza type")
return pizza
Now, we need to rework on the class PizzaStore
so that it will use the factory.
class PizzaStore:
def order_pizza(self, pizza_type):
""" order and get pizza """
factory = PizzaFactory()
pizza = factory.create_pizza(pizza_type)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
If you see the class PizzaStore
it's clean and if we add a new pizza type also it will work without changing the code.
You can find the complete code at github https://github.com/AnjaneyuluBatta505/learnbatta/blob/master/python/design_patterns/creational_design_patterns/factory_method.py