Imagine you are developing a desktop application that supports both Windows and macOS.
Your application needs:
Windows:
Button
Checkbox
TextBox
macOS:
Button
Checkbox
TextBox
The problem is not simply creating one object. The application needs to create a family of related objects that belong to the same environment.
A Windows button should work naturally with Windows checkboxes. A macOS button should work with macOS checkboxes.
This is where the Abstract Factory Design Pattern becomes useful.
Refactoring.Guru defines Abstract Factory as a creational pattern that allows applications to produce families of related objects without specifying their concrete classes.
What Is Abstract Factory?
The Abstract Factory pattern provides an interface for creating multiple related products.
Instead of having:
Create Windows Button
Create Windows Checkbox
Create Windows TextBox
directly throughout the application, we define a factory:
GUI Factory
|
+---- create_button()
|
+---- create_checkbox()
|
+---- create_textbox()
Then provide concrete factories:
WindowsFactory
|
+---- WindowsButton
+---- WindowsCheckbox
+---- WindowsTextBox
MacFactory
|
+---- MacButton
+---- MacCheckbox
+---- MacTextBox
The client works with the abstract factory and does not need to know which concrete family is being created.
Python Example
First, define abstract products:
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def render(self):
pass
class Checkbox(ABC):
@abstractmethod
def render(self):
pass
Now create Windows products:
class WindowsButton(Button):
def render(self):
print("Rendering Windows button")
class WindowsCheckbox(Checkbox):
def render(self):
print("Rendering Windows checkbox")
And macOS products:
class MacButton(Button):
def render(self):
print("Rendering macOS button")
class MacCheckbox(Checkbox):
def render(self):
print("Rendering macOS checkbox")
Next, define the abstract factory:
class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
Create the Windows factory:
class WindowsFactory(GUIFactory):
def create_button(self):
return WindowsButton()
def create_checkbox(self):
return WindowsCheckbox()
Create the macOS factory:
class MacFactory(GUIFactory):
def create_button(self):
return MacButton()
def create_checkbox(self):
return MacCheckbox()
Now the application can work with either family:
factory = WindowsFactory()
button = factory.create_button()
checkbox = factory.create_checkbox()
button.render()
checkbox.render()
The client does not directly instantiate WindowsButton() or WindowsCheckbox(). Instead, it works through the factory.
Why Is It Called a "Family"?
This is the most important concept to understand.
Suppose you have a furniture application. Each furniture style contains:
Modern:
Modern Chair
Modern Sofa
Modern Table
Victorian:
Victorian Chair
Victorian Sofa
Victorian Table
These are families of related products.
Refactoring.Guru uses a similar furniture example and explains that each concrete factory corresponds to a particular product variant.
The factory guarantees that the products belong to the same family.
ModernFactory
|
+--> ModernChair
+--> ModernSofa
+--> ModernTable
This is different from simply creating different types of objects independently.
Dark Mode and Light Mode
Another practical example is a UI system supporting themes.
Light Theme
LightButton
LightCheckbox
LightMenu
Dark Theme
DarkButton
DarkCheckbox
DarkMenu
Instead of scattering theme-specific object creation throughout the application, we can select one factory:
factory = DarkThemeFactory()
Then:
button = factory.create_button()
checkbox = factory.create_checkbox()
menu = factory.create_menu()
The entire UI receives a consistent family of components.
Abstract Factory vs Factory Method
These two patterns are related but solve different problems.
Factory Method usually focuses on creating one type of product.
Transport Factory
|
+---- Truck
+---- Ship
+---- Airplane
Abstract Factory creates multiple related products.
Windows Factory
|
+---- Button
+---- Checkbox
+---- Menu
A useful way to remember this: Factory Method creates a product; Abstract Factory creates a family of related products.
Advantages
Consistent Product Families — The factory ensures that related products belong to the same variant.
Reduced Coupling — Client code depends on abstract interfaces rather than concrete classes.
Easy Environment Switching — The application can switch from Windows to macOS, or from light theme to dark theme, by changing the factory.
Better Scalability — New product families can be introduced through additional concrete factories.
Disadvantages
Abstract Factory can introduce many classes and interfaces. If your application only needs one or two simple objects, this pattern may be unnecessarily complex.
Adding a new product type to every family can also require changes to the abstract factory and all concrete factories.
When Should You Use Abstract Factory?
Consider it when:
- You need multiple related products
- Products must remain compatible with each other
- The application supports multiple environments or platforms
- You want to switch entire product families
- You want client code to remain independent of concrete classes
Conclusion
The Abstract Factory pattern is about creating consistent families of related objects.
The core idea is: choose one factory, and let that factory create all products belonging to the same family.
It is especially useful for cross-platform UI systems, themes, database providers, cloud providers, and applications that support multiple product variants.