Design Patterns Abstract Factory
The Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes. Where the Factory Method creates one product, the Abstract Factory creates a whole set of products that belong together.
The Real-World Analogy
Imagine furnishing a living room. You want everything to match — a modern sofa, a modern coffee table, and a modern lamp. You do not pick pieces from a modern catalogue and a vintage catalogue randomly, because they would clash. An Abstract Factory is like a furniture showroom that only stocks one complete style — you order from one showroom and everything arrives in the same design family.
Abstract Factory vs Factory Method
Factory Method: Creates ONE product (e.g., a Button) Abstract Factory: Creates a FAMILY of products (e.g., Button + Checkbox + TextBox) All products in the family are designed to work together.
UML Diagram
«interface»
┌────────────────────────────────────┐
│ GUIFactory │ ← Abstract Factory
├────────────────────────────────────┤
│ + createButton(): Button │
│ + createCheckbox(): Checkbox │
└────────────┬───────────────────────┘
│ implements
┌────────┴────────┐
│ │
┌────┴──────────┐ ┌───┴─────────────┐
│ WinFactory │ │ MacFactory │ ← Concrete Factories
├───────────────┤ ├─────────────────┤
│+createButton()│ │+createButton() │
│+createCheckbox│ │+createCheckbox()│
└───┬───────────┘ └──────┬──────────┘
│ │
▼ ▼
WindowsButton MacButton ← Concrete Products (Button family)
WindowsCheckbox MacCheckbox ← Concrete Products (Checkbox family)
│ │
└──────────┬──────────┘
│ implements
┌────┴──────┐ ┌────────────────┐
│ Button │ │ Checkbox │ ← Product Interfaces
└───────────┘ └────────────────┘
How the Pattern Flows
Configuration says: OS = "Windows"
│
▼
Application picks WinFactory
│
▼
app.createUI(factory)
│
├── factory.createButton() → WindowsButton
└── factory.createCheckbox() → WindowsCheckbox
WindowsButton + WindowsCheckbox always look and behave the same way.
They were built to work together.
Code Example (pseudocode)
// Abstract products
interface Button { render(); }
interface Checkbox { render(); }
// Concrete products — Windows family
class WindowsButton implements Button { render() { /* Win style */ } }
class WindowsCheckbox implements Checkbox { render() { /* Win style */ } }
// Concrete products — Mac family
class MacButton implements Button { render() { /* Mac style */ } }
class MacCheckbox implements Checkbox { render() { /* Mac style */ } }
// Abstract factory
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
// Concrete factories
class WinFactory implements GUIFactory {
Button createButton() { return new WindowsButton(); }
Checkbox createCheckbox(){ return new WindowsCheckbox();}
}
class MacFactory implements GUIFactory {
Button createButton() { return new MacButton(); }
Checkbox createCheckbox(){ return new MacCheckbox();}
}
// Application — knows nothing about concrete classes
class Application {
Button button;
Checkbox checkbox;
Application(GUIFactory factory) {
button = factory.createButton();
checkbox = factory.createCheckbox();
}
render() {
button.render();
checkbox.render();
}
}
// Client code
GUIFactory factory;
if (OS == "Windows") factory = new WinFactory();
else factory = new MacFactory();
Application app = new Application(factory);
app.render();
Adding a New Family
BEFORE (only 2 families): AFTER (adding Linux family):
────────────────────────── ──────────────────────────────────
WinFactory → Win products WinFactory → Win products
MacFactory → Mac products MacFactory → Mac products
LinuxFactory → Linux products ← NEW
Steps to add Linux family:
1. Create LinuxButton implements Button
2. Create LinuxCheckbox implements Checkbox
3. Create LinuxFactory implements GUIFactory
4. Add "Linux" branch in client config check
Zero changes to existing factories or application code.
When Families Must Stay Consistent
CORRECT (products from the same factory): WinFactory → WindowsButton + WindowsCheckbox ✓ consistent look WRONG (mixing factories): WinFactory → WindowsButton + MacCheckbox ✗ visual mismatch
The Abstract Factory enforces consistency automatically. Because you pick one factory object and use it for all creation calls, mismatches become impossible at the code level.
Real-World Uses
- Cross-platform UI toolkits — Produce native controls for Windows, macOS, and Linux from one abstract interface.
- Database abstraction layers — Generate matching Connection, Command, and Reader objects for MySQL, PostgreSQL, or SQLite.
- Theme engines — Create complete sets of dark-mode or light-mode components that all belong to the same visual theme.
- Game engines — Build matching terrain tiles, character sprites, and sound effects for different game worlds.
Advantages and Disadvantages
ADVANTAGES DISADVANTAGES ────────────────────────────────────── ──────────────────────────────────── Products in a family always match Adding a NEW product type to the Swapping the whole family is easy family requires changing every Client code stays free of concrete concrete factory class class names Follows the Open/Closed Principle More classes to write upfront (add families without editing code)
Key Takeaways
- Abstract Factory creates whole families of related objects, not just one object.
- All products from one factory are designed to work together.
- Swapping an entire family (e.g., from Windows UI to Mac UI) means changing only one factory object.
- Client code only depends on interfaces, never on concrete product classes.
