Yayun Liu's Blog Engineer, Blogger, Learner, Runner

Design patterns in Python: Factory Pattern

7 minutes to read
2023-06-07

Introduction

Design patterns are shared among programmers and continue to be improved over time, thanks to the Gang of Four book Design Patterns: Elements of Reusable Object-Oriented by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.

Design patterns help narrow down the most effective ways of building a given application and offer examples of the same design pattern to improve your application.

There are 23 design patterns, split into three categories: creational, structural, and behavioral, used in OOP, which are highly useful guidelines in software engineering.

Factory design pattern

This post focuses on the factory design pattern, which simplifies object creation by hiding its instantiation from clients.

Factory design reduces complexity by separating object creation from object use and come in two forms, namely, factory method and abstract factory. The factory method returns a different object per input parameter while the abstract factory is a group of factory methods that create a related family of objects. The following section will cover the factory method theory.

The factory method

The factory method is based on a single function that’s written to handle our object creation task. We execute it, passing a parameter that provides information about what we want. As a result, the object we wanted is created.

An example of the factory method pattern that’s used in real life is in the context of a plastic toy construction kit. The molding material that’s used to construct plastic toys is the same, but different toys (different figures or shapes) can be produced using the right plastic molds. This is like having a factory method in which the input is the name of the toy that we want (for example, duck or car) and the output (after the molding) is the plastic toy that was requested.

The abstract factory

The abstract factory design pattern is a generalization of the factory method. An abstract factory is a (logical) group of factory methods, where each factory method is responsible for generating a different kind of object. In this section, we are going to discuss some examples, use cases, and a possible implementation of this pattern.

The abstract factory is used in car manufacturing. The same machinery is used for stamping the parts (doors, panels, hoods, fenders, and mirrors) of different car models. The model that is assembled by the machinery is configurable and easy to change at any time.

Participants

The abstract factory pattern consists of the following components:

  • Abstract Factory:
    • declares an interface for operations that create abstract product objects.
  • Concrete Factory:
    • implements the operations to create concrete product objects.
    • each concrete factory is responsible for creating a family of related objects
  • Abstract Product:
    • declares the common interface for the products created by the Abstract Factory.
  • Concrete Product:
    • defines a product object to be created by the corresponding concrete factory.
    • implements the Abstract Product interfaces.
  • Client:
    • uses only interfaces declared by Abstract Factory and Abstract Product classes.

Structure

The following picture illustrates the relationships among the components of the abstract factory pattern. Factory-pattern

A factory pattern example

In the example below, the Abstract Products are Chair and Table, with their corresponding Concrete Product implementations (VictorianChair, VictorianTable, ModernChair, ModernTable). The Abstract Factory is represented by the FurnitureFactory interface, which declares methods for creating Chair and Table objects. The Concrete Factories (VictorianFurnitureFactory, ModernFurnitureFactory) implement the Abstract Factory and provide the specific implementations of creating related objects.

The client code uses the create_furniture function, which takes a factory as an argument and creates a Chair and Table using that factory.

Code example:

from abc import ABC, abstractmethod

# Abstract Products
class Chair(ABC):
    @abstractmethod
    def sit_on(self):
        pass

class Table(ABC):
    @abstractmethod
    def put_on(self):
        pass

# Concrete Products
class VictorianChair(Chair):
    def sit_on(self):
        print("Sitting on a Victorian Chair")

class VictorianTable(Table):
    def put_on(self):
        print("Putting something on a Victorian Table")

class ModernChair(Chair):
    def sit_on(self):
        print("Sitting on a Modern Chair")

class ModernTable(Table):
    def put_on(self):
        print("Putting something on a Modern Table")

# Abstract Factory
class FurnitureFactory(ABC):
    @abstractmethod
    def create_chair(self) -> Chair:
        pass

    @abstractmethod
    def create_table(self) -> Table:
        pass

# Concrete Factories
class VictorianFurnitureFactory(FurnitureFactory):
    def create_chair(self) -> Chair:
        return VictorianChair()

    def create_table(self) -> Table:
        return VictorianTable()

class ModernFurnitureFactory(FurnitureFactory):
    def create_chair(self) -> Chair:
        return ModernChair()

    def create_table(self) -> Table:
        return ModernTable()

# Client code
def create_furniture(factory: FurnitureFactory):
    chair = factory.create_chair()
    table = factory.create_table()
    return chair, table

# Using the factories
victorian_factory = VictorianFurnitureFactory()
modern_factory = ModernFurnitureFactory()

victorian_chair, victorian_table = create_furniture(victorian_factory)
modern_chair, modern_table = create_furniture(modern_factory)

The illustration of the code example

Factory-pattern-illustration


Comments

Content