Back to All Design Patterns
Pattern 2 of 22
Creational PatternINTERMEDIATE8 min deep dive
Abstract Factory Pattern
Provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Real-World Mental Model / Metaphor:
A modern furniture store with Victorian, Modern, and Art Deco lines. Ordering a 'Sofa + Chair + CoffeeTable' from ModernFactory guarantees all 3 pieces match in style.
Interactive Runtime Simulator
Test and tweak inputs dynamicallyInteractive Abstract Factory SimulatorLIVE PLAYGROUND
Interact with the controls below to see how this design pattern executes in memory at runtime.
Switch Target Factory Platform:
The client code only interacts with
GUIFactory.createButton() and GUIFactory.createCheckbox(). It never couples directly to concrete classes!CONCRETE PRODUCTS CREATEDmac
Rendered Button:Rendered Checkbox:
The Problem It Solves
Preventing mismatched components (e.g. putting a Victorian Gothic chair in a Minimalist Scandinavian living room or combining a Windows button with a macOS scrollbar).
The Architectural Solution
Declare an abstract factory interface with a creation method for each distinct product type in the family.
Pattern Structure & Participants
| Participant | Role & Responsibility | Type |
|---|---|---|
| GUIFactory (Interface) | Declares createButton() and createCheckbox() | interface |
| WinFactory / MacFactory | Implements creation for Windows or macOS components | class |
| Button / Checkbox (Interfaces) | Abstract product families | interface |
| WinButton, MacButton, etc. | Concrete implementations | class |
Collaboration Rules:
- Client receives GUIFactory via dependency injection
- Client instantiates matched Button + Checkbox through the same factory instance
Production Code Implementation
Abstract Factory.java
// Product Families
public interface Button { void render(); }
public interface Checkbox { void render(); }
// Concrete Windows Products
public class WinButton implements Button {
public void render() { System.out.println("Rendering Windows Flat UI Button"); }
}
public class WinCheckbox implements Checkbox {
public void render() { System.out.println("Rendering Windows Metro Checkbox"); }
}
// Concrete Mac Products
public class MacButton implements Button {
public void render() { System.out.println("Rendering macOS Aqua Rounded Button"); }
}
public class MacCheckbox implements Checkbox {
public void render() { System.out.println("Rendering macOS Blue Accent Checkbox"); }
}
// Abstract Factory
public interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// Concrete Factories
public class WinFactory implements GUIFactory {
public Button createButton() { return new WinButton(); }
public Checkbox createCheckbox() { return new WinCheckbox(); }
}
public class MacFactory implements GUIFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
} When to Use:
- •When your system must be independent of how its products are created, composed, and represented.
- •When your system needs to be configured with one of multiple product families.
- •When you want to enforce that products from the same family are used together.
When to Avoid (Anti-Pattern):
- •When you only have a single product line that will never branch into variants.
- •When adding new products to the family is frequent (requires updating all concrete factories).
Staff Engineering Interview Insights & Gotchas
- Interviewers love asking how to add a third cloud provider (e.g. GCP) to an existing AWS/Azure Abstract Factory.
- Explain how Abstract Factory relates to Dependency Injection: you inject the factory into client constructors.