Design Pattern: Abstract Factory Pattern in Python

We use the Abstract factory pattern when we have to generate multiple types of objects using the factory pattern. Abstract factory pattern works as a logical group for the Factory pattern.

Abstract factory is used to generate multiple types of factories, and those factories are used to generate the desired item objects.

NOTES

Abstract factory pattern works as a factory of the Factory pattern, so before learning the details of the Abstract factory pattern make sure to have a clear idea about the Factory pattern.

As the abstract factory works as a factory, so we get the full benefit of using a Factory pattern.

NOTES

In this article, we discuss the implementation of the Abstract Factory Pattern in Python.

See the Abstract Factory in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Abstract Factory Pattern-

Implementation

For the implementation of the Abstract factory pattern, we have to work on 2 layers. First, we have to implement the process of creating factories, and then the factory can be used to generate item objects.

Create an abstract class(or protocol, if you prefer) for the items.
Create the item classes and inherit the abstract class.
Create an abstract class(or protocol) for the factories.
Create the factory classes and inherit from the factory abstract class.
In the factory classes, create item object based on the provided criteria, and return that.
Create a factory producer class. In the class create a method that generates a factory object and returns that.

Here is how the parts of the implementation of an Abstract Factory pattern look like-

Abstract Factory Pattern Implementation
Abstract Factory Pattern Implementation

Here is a general implementation of the Abstract factory pattern in Python-

from abc import ABC, abstractmethod
from typing import Optional


# Item Abstract class
class Item(ABC):
    @abstractmethod
    def operation1(self) -> None:
        pass

    @abstractmethod
    def operation2(self) -> None:
        pass


# Item of type 1
class Type1Item1(Item):
    def operation1(self) -> None:
        print("Type 1 Item 1: executing operation 1")

    def operation2(self) -> None:
        print("Type 1 Item 1: executing operation 2")


# Item of type 1
class Type1Item2(Item):
    def operation1(self) -> None:
        print("Type 1 Item 2: executing operation 1")

    def operation2(self) -> None:
        print("Type 1 Item 2: executing operation 2")


# Item of type 2
class Type2Item1(Item):
    def operation1(self) -> None:
        print("Type 2 Item 1: executing operation 1")

    def operation2(self) -> None:
        print("Type 2 Item 1: executing operation 2")


# Item of type 2
class Type2Item2(Item):
    def operation1(self) -> None:
        print("Type 2 Item 2: executing operation 1")

    def operation2(self) -> None:
        print("Type 2 Item 2: executing operation 2")


# Factory Protocol
class Factory(ABC):
    @abstractmethod
    def get_item(self, item_identifier: str) -> Optional[Item]:
        pass


# Type 1 Factory
class Type1Factory(Factory):
    def get_item(self, item_identifier: str) -> Optional[Item]:
        match item_identifier:
            case "item1":
                return Type1Item1()
            case "item2":
                return Type1Item2()
            case _:
                return None


# Type 2 Factory
class Type2Factory(Factory):
    def get_item(self, item_identifier: str) -> Optional[Item]:
        match item_identifier:
            case "item1":
                return Type2Item1()
            case "item2":
                return Type2Item2()
            case _:
                return None


# Factory producter - Factory of Factory
class FactoryProducer:
    @staticmethod
    def get_factory(factory_type: int) -> Optional[Factory]:
        match factory_type:
            case 1:
                return Type1Factory()
            case 2:
                return Type2Factory()
            case _:
                None


# Demo usage
def main() -> None:
    factory1 = FactoryProducer.get_factory(1)

    first_item = factory1.get_item("item1")

    if first_item is not None:
        first_item.operation1()
        first_item.operation2()

    factory2 = FactoryProducer.get_factory(2)

    second_item = factory2.get_item("item1")

    if second_item is not None:
        second_item.operation1()

    third_item = factory2.get_item("item2")

    if third_item is not None:
        third_item.operation1()
        third_item.operation2()


if __name__ == "__main__":
    main()
Python

Output:

Type 1 Item 1: executing operation 1
Type 1 Item 1: executing operation 2

Type 2 Item 1: executing operation 1

Type 2 Item 2: executing operation 1
Type 2 Item 2: executing operation 2
Plaintext

Examples

In the implementation section, we saw a general implementation. In the example section let’s see how we can

Example #1: Transport

In this example we have 2 types of transport-

  • Two wheeler vehicles
  • Four wheeler vehicles

So we created 2 factories- 1 for each type of vehicle.

But first, let’s create the item classes.

Transport Abstract class[Item Interface]

Create class “Transport“.
Inherit from ‘abc.ABC‘, to make it an abstract class. You can make it a protocol if you prefer.
Declare methods required by the item classes, and make those methods abstract by using “@abstractmethod“.
from abc import ABC, abstractmethod
from typing import Optional


class Transport(ABC):
    @abstractmethod
    def start(self) -> None:
        pass

    @abstractmethod
    def stop(self) -> None:
        pass

    @abstractmethod
    def repair(self) -> None:
        pass
Python

Bicycle Class [Concrete Item Class]

Create item class “Bicycle“.
Inherit form the “Transport” class.
Implement the abstract methods. Also implement any method that is required specifically for the bicycle.
class Bicycle(Transport):
    def start(self) -> None:
        print("Bicycle started")

    def stop(self) -> None:
        print("Bicycle stopped")

    def repair(self) -> None:
        print("Repairing Bicycle")
Python

Motorcycle Class [Concrete Item Class]

Create item class “Motorcycle“.
Inherit form the “Transport” class.
Implement the abstract methods.
class Motorcycle(Transport):
    def start(self) -> None:
        print("Motorcycle started")

    def stop(self) -> None:
        print("Motorcycle stopped")

    def repair(self) -> None:
        print("Repairing Motorcycle")
Python

Car Class [Concrete Item Class]

Create item class “Car“.
Inherit form the “Transport” class.
Implement the abstract methods.
class Car(Transport):
    def start(self) -> None:
        print("Car started")

    def stop(self) -> None:
        print("Car stopped")

    def repair(self) -> None:
        print("Repairing Car")
Python

Truck Class [Concrete Item Class]

Create item class “Truck“.
Inherit form the “Transport” class. Implement the abstract methods.
class Truck(Transport):
    def start(self) -> None:
        print("Truck started")

    def stop(self) -> None:
        print("Truck stopped")

    def repair(self) -> None:
        print("Repairing Truck")
Python

Abstract Transport Factory[Factory Interface]

Create class “TransportFactory“.
Inherit from “abc.ABC” to make it an abstract class.
Declare abstract method “get_transport“, and accept a param named “transport_type”.
class TransportFactory(ABC):
    @abstractmethod
    def get_transport(self, transport_type: str) -> Optional[Transport]:
        pass
Python

Two-Wheel Transport Factory Class [Concrete Factory Class]

Create class “TwoWheelerTransportFactory“.
Inherit from “TransportFactory“.
Implement the method “get_transport“. Based on the “transport_type” value, create an object of “Bicycle” or “Motorcycle“, and return that.
class TwoWheelerTransportFactory(TransportFactory):
    def get_transport(self, transport_type: str) -> Optional[Transport]:
        match transport_type:
            case "bicycle":
                return Bicycle()
            case "motorcycle":
                return Motorcycle()
            case _:
                return None
Python

Four-Wheel Transport Factory Class [Concrete Factory Class]

Create class “FourWheelerTransportFactory“.
Inherit from “TransportFactory“.
Implement the method “get_transport“. Based on the “transport_type” value, create an object of “Car” or “Truck“, and return that.
class FourWheelerTransportFactory(TransportFactory):
    def get_transport(self, transport_type: str) -> Optional[Transport]:
        match transport_type:
            case "car":
                return Car()
            case "truck":
                return Truck()
            case _:
                return None
Python

Factory Producer Class [Producer]

Create the class “FactoryProducer“.
Create static method “get_factory“.
Accept param “number_of_wheels” in the “get_factory” method.
Based on the value of “number_of_wheels“, create an object of one of the “TransportFactory” concrete classes, and return that.
class FactoryProducer:
    @staticmethod
    def get_factory(number_of_wheels: int) -> Optional[TransportFactory]:
        match number_of_wheels:
            case 2:
                return TwoWheelerTransportFactory()
            case 4:
                return FourWheelerTransportFactory()
            case _:
                None
Python

Demo

Here is how we can use our implementation of the Abstract Factory pattern-

# Demo usage
def main() -> None:
    two_wheeler_transport_factory = FactoryProducer.get_factory(2)

    if two_wheeler_transport_factory is not None:
        first_transport = two_wheeler_transport_factory.get_transport("bicycle")

        if first_transport:
            first_transport.start()
            first_transport.stop()

    four_wheeler_transport_factory = FactoryProducer.get_factory(4)

    if four_wheeler_transport_factory is not None:
        second_transport = four_wheeler_transport_factory.get_transport("truck")

        if second_transport:
            second_transport.start()
            second_transport.stop()
            second_transport.repair()


if __name__ == "__main__":
    main()
Python

Output:

Bicycle started
Bicycle stopped

Truck started
Truck stopped
Repairing Truck
Plaintext

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check the implementation of the Abstract Factory pattern in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.