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.
Here is how the parts of the implementation of an Abstract Factory pattern look like-
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()
PythonOutput:
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
PlaintextExamples
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]
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
PythonBicycle Class [Concrete Item Class]
class Bicycle(Transport):
def start(self) -> None:
print("Bicycle started")
def stop(self) -> None:
print("Bicycle stopped")
def repair(self) -> None:
print("Repairing Bicycle")
PythonMotorcycle Class [Concrete Item Class]
class Motorcycle(Transport):
def start(self) -> None:
print("Motorcycle started")
def stop(self) -> None:
print("Motorcycle stopped")
def repair(self) -> None:
print("Repairing Motorcycle")
PythonCar Class [Concrete Item Class]
class Car(Transport):
def start(self) -> None:
print("Car started")
def stop(self) -> None:
print("Car stopped")
def repair(self) -> None:
print("Repairing Car")
PythonTruck Class [Concrete Item Class]
class Truck(Transport):
def start(self) -> None:
print("Truck started")
def stop(self) -> None:
print("Truck stopped")
def repair(self) -> None:
print("Repairing Truck")
PythonAbstract Transport Factory[Factory Interface]
class TransportFactory(ABC):
@abstractmethod
def get_transport(self, transport_type: str) -> Optional[Transport]:
pass
PythonTwo-Wheel Transport Factory Class [Concrete Factory Class]
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
PythonFour-Wheel Transport Factory Class [Concrete Factory Class]
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
PythonFactory Producer Class [Producer]
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
PythonDemo
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()
PythonOutput:
Bicycle started
Bicycle stopped
Truck started
Truck stopped
Repairing Truck
PlaintextSource Code
Use the following link to get the source code:
Example | Source Code Link |
---|---|
Example #1: Transport | GitHub |
Other Code Implementations
Use the following links to check the implementation of the Abstract Factory pattern in other programming languages.