Last Updated: February 21, 2026
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: Buttons, Checkboxes, Text fields, and Menus.
In your first attempt, you might implement platform-specific UI components like this:
Now, in your application logic, you check the operating system and manually instantiate the correct classes:
This setup works when you have two components on two platforms. But it quickly becomes unmanageable.
Nothing stops a developer from writing new WindowsButton() alongside new MacOSCheckbox(). The code compiles, the tests might even pass, and the bug only surfaces when a user sees a visually broken screen.
The client code directly references WindowsButton, MacOSCheckbox, and every other platform-specific class. Every file that creates UI components needs platform-checking logic.
You cannot treat all buttons polymorphically. There is no Button type that WindowsButton and MacOSButton both implement. You cannot write a method that accepts "any button."
Adding Linux means creating LinuxButton, LinuxCheckbox, and updating every conditional block in the codebase. Adding a TextField component means creating WindowsTextField, MacOSTextField, LinuxTextField, and adding more branches everywhere.
Every new platform or component forces you to modify existing code. You cannot extend the system without editing files that already work.
Button and Checkbox interfaces, not concrete classesThis is exactly what the Abstract Factory pattern provides.
The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
The key word is families. Factory Method deals with creating one product at a time. Abstract Factory deals with creating multiple products that must work together. A GUI factory does not just create buttons. It creates buttons, checkboxes, text fields, and menus that all share the same visual style.
The structure involves five participants:
GUIFactory)createButton(), createCheckbox(), createTextField(), etc.WindowsFactory, MacOSFactory)Button, Checkbox)WindowsButton, MacOSButton) will implement these interfaces.WindowsButton, MacOSCheckbox)Application)Here is the Abstract Factory workflow, step by step:
At application startup, a configuration value, environment variable, or runtime check determines which concrete factory to instantiate. This is the only place in the codebase that references concrete factory classes.
The client receives the factory through its constructor. It stores the factory as the abstract type, not a concrete one.
When the client needs a button, it calls factory.createButton(). When it needs a checkbox, it calls factory.createCheckbox(). The client has no idea which concrete classes are being instantiated.
Because the factory is a WindowsFactory, both createButton() and createCheckbox() return Windows-specific components. There is no possibility of getting a macOS checkbox from a Windows factory.
The client calls button.paint() and checkbox.paint(). It does not know or care whether these are Windows or macOS components. The behavior is determined by the factory that was injected in Step 2.
Let's implement the Abstract Factory pattern step by step. We will define abstract product interfaces, create concrete products for two platforms, build an abstract factory with concrete implementations, and wire everything together through a client that never touches a concrete class.
We start with the contracts that all product variants must fulfill. These interfaces are what the client will work with.
Each platform provides its own implementation of every product interface.
The abstract factory declares one creation method per product type. Any concrete factory must implement all of them.
Each concrete factory produces a complete, compatible set of products for its platform.
The client receives a factory through its constructor and uses only abstract interfaces.
The entry point is the only place that references concrete factories. It reads the platform, picks the right factory, and injects it into the client.
Let's build a notification system that supports Email and SMS channels. Each channel produces two related objects: a Message and a Sender. Mixing an email message with an SMS sender would produce garbled output, so family consistency matters.
EmailFactory can only produce email objects. There is no code path that creates an email message paired with an SMS senderPushFactory, PushMessage, and PushSender. Nothing existing changes