Abstract Factory
Abstract Factory is a creational pattern that lets you create families of related objects without specifying their concrete classes. Client code depends only on the factory interface, so which product family gets created is determined at runtime.
βΆArchitecture Diagram
π StructureDashed line animations indicate the flow direction of data or requests
Imagine building a UI toolkit. You have buttons, checkboxes, and text fields, and each needs a Windows version and a macOS version. Handling this with conditionals means `if (os === 'windows') new WindowsButton()` is repeated for every component. When Linux is added, every branch has to be found and updated. The more serious problem is consistency. If a Windows button accidentally appears next to a macOS checkbox, behavior breaks or rendering fails. The issue is that nothing in the code structure guarantees related objects always come from the same variant.
As object-oriented programming spread, new-keyword-based object creation code proliferated. It was not a problem in small programs, but as projects grew and supported more platforms, creation logic mixing into business logic became a recurring pain point. When GoF (Gang of Four) documented Abstract Factory in 1994, the practical motivation was that failing to separate creation responsibility by product family caused the blast radius of changes to spread across the entire codebase whenever a new variant was added. Where Factory Method delegates the creation of individual objects, Abstract Factory gathers the creation of objects that must work together into a single place -- a broader-scope solution.
Abstract Factory pivots on two axes. One is product type (button, checkbox), and the other is product variant (Windows, macOS). First, the AbstractFactory interface declares methods like createButton() and createCheckbox(). Then a ConcreteFactory for each variant (WindowsFactory, MacFactory) implements that interface. WindowsFactory.createButton() returns a WindowsButton; MacFactory.createButton() returns a MacButton. The client works exclusively with the AbstractFactory type. Depending on which ConcreteFactory is injected, the entire set of created objects changes, yet the client code needs no modification. This structure means adding a new variant (Linux) requires only a LinuxFactory and the corresponding Linux product classes.
Factory interface and concrete factories
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WindowsFactory implements GUIFactory {
createButton() { return new WindowsButton(); }
createCheckbox() { return new WindowsCheckbox(); }
}
class MacFactory implements GUIFactory {
createButton() { return new MacButton(); }
createCheckbox() { return new MacCheckbox(); }
}A single GUIFactory interface defines the creation of the entire product family. When the client receives a WindowsFactory, only Windows objects are produced; when it receives a MacFactory, only Mac objects come out.
Client code
function renderUI(factory: GUIFactory) {
const button = factory.createButton();
const checkbox = factory.createCheckbox();
button.render();
checkbox.render();
}
// Swapping the factory at runtime replaces the entire product family
const factory = os === 'windows'
? new WindowsFactory()
: new MacFactory();
renderUI(factory);The renderUI function knows nothing about concrete classes. Branching exists only at the single point where the factory is selected.
Abstract Factory and Factory Method both encapsulate object creation, but they differ in scope. Factory Method is a pattern where one method delegates the creation of one object to a subclass, while Abstract Factory is a pattern that groups the creation of multiple related objects into a product family. The decision criterion is straightforward. If you need to create a single object whose implementation varies, Factory Method is sufficient. But if you have multiple objects that must be used together and must not be mixed -- like buttons and checkboxes -- Abstract Factory is needed. Abstract Factory has a limitation too. Adding a new product type (e.g., Slider) requires modifying all factory interfaces and their implementations. It is not well suited to situations where product types change frequently.
Commonly Compared Concepts
Factory Method
A creational pattern that delegates object creation to subclasses
Factory Method delegates the creation of a single object to subclasses, while Abstract Factory groups the creation of multiple related objects into product-family-level creation.
Builder
A pattern that separates the construction of a complex object into steps
Abstract Factory decides which product family to create, while Builder assembles a single complex object step by step. The concerns split into 'what to create' versus 'how to assemble.'
Abstract Factory appears most often when the same application must work across multiple environments or configurations. Replacing OS-specific UI components in a cross-platform desktop app, or switching database-vendor-specific objects through a factory in a data access module, are representative examples. It is also useful for testing. In production you use a factory that creates real HTTP clients and DB connections; in tests you swap in a factory that creates mock objects, changing all dependencies without touching client code. The signal for adopting this pattern is 'conditional code that creates related objects as a group is repeated in multiple places, and the blast radius widens every time a new variant is added.' Conversely, when product types themselves change frequently or the combination constraints between objects are weak, the benefits of this pattern diminish.