- Published on
[Creational] Abstract Factory
Abstract Factory Design Pattern
The Abstract Factory pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It helps enforce consistency among products and makes it easier to introduce new variants without modifying existing code.
Structure
Abstract Factory (
AbstractFactory)- Declares a set of methods to create abstract products.
Concrete Factories (
ConcreteFactoryA,ConcreteFactoryB)- Implements the abstract factory to create specific product variants.
Abstract Products (
AbstractProductX,AbstractProductY)- Defines interfaces for product families.
Concrete Products (
ProductAX,ProductAY,ProductBX,ProductBY)- Implements product interfaces with specific variations.
Client (
Client)- Uses the factory to create product objects without needing to know their concrete classes.
Example: GUI Factory
Let's implement an abstract factory that creates UI elements (Button and Checkbox) for different operating systems (Windows and Mac).
Step 1: Define Abstract Products
from abc import ABC, abstractmethod
# Abstract Product A
class Button(ABC):
@abstractmethod
def render(self) -> str:
pass
# Abstract Product B
class Checkbox(ABC):
@abstractmethod
def render(self) -> str:
pass
Step 2: Define Concrete Products
# Concrete Product A1
class WindowsButton(Button):
def render(self) -> str:
return "Rendering a Windows-style button"
# Concrete Product A2
class MacButton(Button):
def render(self) -> str:
return "Rendering a Mac-style button"
# Concrete Product B1
class WindowsCheckbox(Checkbox):
def render(self) -> str:
return "Rendering a Windows-style checkbox"
# Concrete Product B2
class MacCheckbox(Checkbox):
def render(self) -> str:
return "Rendering a Mac-style checkbox"
Step 3: Define Abstract Factory
# Abstract Factory
class UIFactory(ABC):
@abstractmethod
def create_button(self) -> Button:
pass
@abstractmethod
def create_checkbox(self) -> Checkbox:
pass
Step 4: Implement Concrete Factories
# Concrete Factory 1 - Windows Factory
class WindowsFactory(UIFactory):
def create_button(self) -> Button:
return WindowsButton()
def create_checkbox(self) -> Checkbox:
return WindowsCheckbox()
# Concrete Factory 2 - Mac Factory
class MacFactory(UIFactory):
def create_button(self) -> Button:
return MacButton()
def create_checkbox(self) -> Checkbox:
return MacCheckbox()
Step 5: Create Client Code
# Client Code
def client_code(factory: UIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
print(button.render())
print(checkbox.render())
# Testing
windows_factory = WindowsFactory()
mac_factory = MacFactory()
print("Windows UI:")
client_code(windows_factory)
print("\nMac UI:")
client_code(mac_factory)
Output
Windows UI:
Rendering a Windows-style button
Rendering a Windows-style checkbox
Mac UI:
Rendering a Mac-style button
Rendering a Mac-style checkbox
Advantages of Abstract Factory Pattern
✅ Encapsulation of Object Creation – The client does not need to know the concrete classes. ✅ Consistency among Products – Ensures that products in a family match. ✅ Easy to Introduce New Variants – New factories can be added without modifying existing client code. ✅ Promotes Separation of Concerns – Factories manage object creation, while products handle their own behavior.
When to Use?
- When you need to create families of related objects.
- When enforcing consistency among related objects is essential.
- When the system should be independent of how its objects are created.