The Abstract Factory Design Pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.
It’s particularly useful in situations where:
The Abstract Factory Pattern encapsulates object creation into factory interfaces.
Each concrete factory implements the interface and produces a complete set of related objects. This ensures that your code remains extensible, consistent, and loosely coupled to specific product implementations.
Let’s walk through a real-world example to see how we can apply the Abstract Factory Pattern to build a system that’s flexible, maintainable, and able to support multiple interchangeable product families without conditional logic.
Imagine you're building a cross-platform desktop application that must support both Windows and macOS.
To provide a good user experience, your application should render native-looking UI components for each operating system like:
In your first attempt, you might implement platform-specific UI components like this:
Then, in your application logic, you end up doing something like:
While this setup looks simple for two UI components on two platforms, it quickly becomes a nightmare as your app grows.
Your main application logic is tightly bound to platform-specific classes (WindowsButton
, MacOSCheckbox
, etc.). This means everywhere you create UI components, you must check the OS manually.
You can’t treat buttons or checkboxes generically. There’s no common interface like Button
or Checkbox
to work with.
Each platform-specific block replicates similar logic — instantiating buttons, checkboxes, menus, etc. You'll repeat this conditional branching throughout your codebase.
What happens when you:
TextField
, Slider
, MenuBar
)?You’ll have to:
Any new variant requires modifying existing code. Your UI creation logic is not open for extension but very much open to breaking changes.
We need a way to:
This is where the Abstract Factory Pattern comes in.
The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
In our case, we want to create a family of UI components (like Button
, Checkbox
, TextField
, etc.) that look and behave differently on different platforms (such as Windows or macOS) but expose the same interface to the application.
GUIFactory
)createButton()
, createCheckbox()
, createTextField()
, etc.WindowsFactory
, MacOSFactory
)Button
, Checkbox
)WindowsButton
, MacOSButton
) will implement these interfaces.WindowsButton
, MacOSCheckbox
)Application
)Let’s implement a system where our app can generate native-looking UI components (buttons, checkboxes) for Windows and macOS without hardcoding platform checks or duplicating logic.
We start by defining the product interfaces used by the client.
These implement the platform-specific logic.
This is the interface for creating families of related products.
Each factory creates platform-specific component variants.
The client code uses the factory to create UI components. It doesn't care which OS it is dealing with.