×

Factory Method – Design Pattern with Python

Factory Design Patterns Python Feature

Factory Method is a creational design pattern that asks us to define an interface for creating an object, called Factory interface. These interfaces define the generic structure, but don’t initialize objects. The initialization is left to do by more specific subclasses.

Factory Method Design Pattern 1

The main motivation behind the Factory Method Design Pattern is to enhance loose coupling in code through the creation of an abstract class that will be used to create different types of objects that share some common attributes and functionality.

The best time to use the factory method pattern is when you have multiple variations of a single entity.

Let us understand where to use the factory method design pattern with an example, let’s say there is a Person(Client) who wants to calculate the area and the circumference of different shapes, let’s first define how our shape class should look like.

Consider the abstract base class Shape for all of our shapes, below:

from abc import ABC
class Shape(ABC):
    @abstractmethod
    def calculate_area(self):
        pass

    @abstractmethod
    def calculate_circumference(self):
        pass

Limiting the client only to the two shapes i.e. Square and Circle. That means there are two Providers Square and Circle, who can help the client.

class Square(Shape):
    def __init__(self, width):
        self.width = width

    def calculate_area(self):
        return self.width ** 2

    def calculate_circumference(self):
        return 4 * self.width

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def calculate_area(self):
        return 3.14 * self.radius * self.radius

    def calculate_circumference(self):
        return 2 * 3.14 * self.radius

Now to communicate with each provider, the client must know how both providers are implemented. And if in case there are ‘n’ providers, for ‘n’ different shapes, he must know the all ‘n’ implementation. Consider the call to the Square and Circle below –

squr = Square(4)
squr.calculate_area()
squr.calculate_circumference()

circle = Circle(5)
circle.calculate_area()
circle.calculate_circumference()

Two constructor calls for the classes(providers) having little variation in their functionality. This is where we can introduce the Factory method to centralize and encapsulate the object creation. That will help the client because now he had to know only about the factory rather than keeping knowledge about all ‘n’ implementations.

Let’s create the Factory interface ShapeFactory and shapes_client

#The Factory Interface
class ShapeFactory:
    def create_shape(self, name, width):
        if name == 'square':
            return Square(int(width))
            
        elif name == 'circle':
            return Circle(float(width))

#Interface that will deal with client
def shapes_client():
    shape_factory = ShapeFactory()
    shape_name = 'circle'
    widthOrRadius = 10
    shape = shape_factory.create_shape(shape_name, widthOrRadius)

    print(shape.calculate_area())
    print(shape.calculate_circumference())      

Here the client doesn’t need to call the constructors of concrete classes, rather the client have to call the Factory interface and asks it to solve his problem(finding area and the circumference). The client doesn’t have to know anything about the object creation or its specifics.

Using the factory interface, a client can create objects with minimal knowledge of how objects work. However, the Factory interface has two parts( ShapeFactory and shapes_client) one to deal with providers(actual concrete classes) and the other with clients.

The factory interface is like a translator, which is dedicatedly introduced to communicate on behalf of the client, here are two things to note, first factory interface has to know about all the different implementations of concrete classes and second, a client could be any separate entity like a high-level module.

Pros and Cons of Factory Method – Design Patterns

Pros

  • New types of products can be easily added without disturbing the existing client code, due to loosely coupled entities.
  • Helps to uphold the Single Responsibility Principle where classes and objects handles specific functionality.

Cons

  • To create a particular concrete product object, the client might have to create the sub-class for the creator class.
  • Creation of more classes eventually leads to less readability, though maintainable.