What It Is
The Abstract Factory pattern creates whole families of related objects that belong together. Where a factory method makes one product, an abstract factory makes a matching set — and guarantees the pieces are never mixed.
The classic case is theming: a light theme must produce light buttons and light labels, never a mix.
Example: A Theme Factory
render_screen takes any UIFactory and builds a consistent screen from it. Swapping the whole look is one argument — and mixing themes is impossible by construction.
One factory, one consistent family
The light theme produces only light parts, the dark theme only dark ones. render_screen never changes.
Output: complete Python program
from typing import Protocol
class Button(Protocol):
def render(self) -> str: ...
class Label(Protocol):
def render(self) -> str: ...
# The abstract factory makes a whole matching family.
class UIFactory(Protocol):
def new_button(self) -> Button: ...
def new_label(self) -> Label: ...
class LightButton:
def render(self) -> str:
return "[ OK ] light button"
class LightLabel:
def render(self) -> str:
return "hello light label"
class DarkButton:
def render(self) -> str:
return "[ OK ] dark button"
class DarkLabel:
def render(self) -> str:
return "hello dark label"
class LightTheme:
def new_button(self) -> Button:
return LightButton()
def new_label(self) -> Label:
return LightLabel()
class DarkTheme:
def new_button(self) -> Button:
return DarkButton()
def new_label(self) -> Label:
return DarkLabel()
def render_screen(factory: UIFactory) -> None:
print(factory.new_label().render())
print(factory.new_button().render())
render_screen(LightTheme())
render_screen(DarkTheme())
When to Use It
Use it when several objects must stay consistent with each other — themes, platform widget sets, matching import/export format pairs.
Skip it when the products do not need to match. Independent objects deserve independent constructors, not a family factory.
Pros and Cons
Pros: family consistency is guaranteed; whole families swap with one value; calling code depends only on protocols.
Cons: a lot of protocols and classes for a small job; adding a new product to the family means touching every factory.