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.

Leave a Comment