Abstract Factory
What This Concept Is
Abstract Factory is a creational pattern that defines an interface for creating a family of related products without binding clients to concrete classes. The guarantee it sells is consistency: every product returned by one factory instance belongs to the same family and is known to work together.
The structure is:
- an
AbstractFactoryinterface with one method per product kind (createButton,createScrollBar,createWindow) - concrete factories (
MacFactory,WindowsFactory) that each return products from their own family - client code that holds an
AbstractFactoryand asks it for products without caring about the concrete family
The problem it absorbs: the client needs several products that must match (a Mac button belongs with a Mac scroll bar, never a Windows one), and the choice of family is made once, high in the call stack.
Why It Matters Here
If Factory Method answers how does one method choose a product, Abstract Factory answers how do we keep an entire object graph in one consistent dialect. It is the canonical answer to cross-platform UI toolkits, multi-dialect database clients, and plugin ecosystems where mixing components from two families would be a correctness bug, not just a style issue.
It also has a sharp misuse story: if there is only one product kind or only one family, Abstract Factory is structural tax with no correctness win.
Concrete Example
interface UIFactory {
createButton(): Button;
createScrollBar(): ScrollBar;
}
class MacFactory implements UIFactory {
createButton() { return new MacButton(); }
createScrollBar() { return new MacScrollBar(); }
}
class WinFactory implements UIFactory {
createButton() { return new WinButton(); }
createScrollBar() { return new WinScrollBar(); }
}
function buildUI(ui: UIFactory) {
const btn = ui.createButton();
const bar = ui.createScrollBar();
// guaranteed to match because ui is one instance
}
const factory: UIFactory = isMac() ? new MacFactory() : new WinFactory();
buildUI(factory);
Structural sketch:
+--------------+ +----------+
| UIFactory |<-------------| Client |
| createButton | +----------+
| createScroll |
+--------------+
^ ^
| |
+---------------+ +---------------+
| MacFactory | | WinFactory |
+---------------+ +---------------+
| | | |
v v v v
MacBtn MacScroll WinBtn WinScroll
One factory is chosen once; all resulting products come from the same family.
Common Confusion / Misconception
The most common confusion is Abstract Factory versus Factory Method:
- Factory Method uses inheritance. A subclass overrides one method to pick one product.
- Abstract Factory uses composition. A client holds a factory object with several related creation methods.
A subtler confusion is Abstract Factory versus Builder. Builder constructs one complex object step by step; Abstract Factory returns several simple objects that must be compatible.
How To Use It
- Identify a set of products that must agree (all Mac, all Windows; all SQL, all NoSQL).
- Define an interface naming one creation method per product kind.
- Write one concrete factory per family.
- Inject the factory at the composition root; never let business code choose the family.
- If a new product kind gets added, every factory must change. Accept that cost only if the product family really is fixed.
Check Yourself
- What correctness property does Abstract Factory protect that Factory Method does not?
- Why is adding a new product kind more painful than adding a new family?
- When is one
enumplus aswitcha better answer?
Mini Drill or Application
Design an Abstract Factory for cross-platform file dialogs with two families (desktop, mobile). Implement:
- the
DialogFactoryinterface withcreateOpenDialogandcreateSaveDialog - two concrete factories returning platform-appropriate dialogs
- a client function that takes the factory as a parameter and never checks the platform
Then delete the interface and rewrite it as one createDialogs(platform) function. Compare readability.