2 min read

Abstract Factory Pattern

The Abstract Factory Pattern is a creational design pattern that lets you produce families of related or dependent objects without specifying their concrete classes.

1. The Core Concept

While the Factory Method creates one product, the Abstract Factory creates a family of products. Clients work with factories and products through abstract interfaces, so they don't need to know which concrete classes they are using.

  • Abstract Factory: Declares an interface for creating each distinct product in a product family.
  • Concrete Factory: Implements the creation methods for a specific variant of the product family.
  • Abstract Product: Declares an interface for a type of product.
  • Concrete Product: Implements the product interface for a specific variant.

2. Analogy: Furniture Shop

Imagine a furniture shop simulator. You have a family of products: Chair, Sofa, CoffeeTable. You also have variants (styles): Modern, Victorian, ArtDeco.

  • If a customer wants a Modern living room, they need a ModernChair, ModernSofa, and ModernCoffeeTable.
  • You don't want to accidentally give them a VictorianChair with a ModernSofa.
  • The ModernFurnitureFactory ensures all products created match the "Modern" style.

3. Example (TypeScript)

Let's build a cross-platform GUI toolkit (Windows vs. Mac).

// Abstract Products
interface Button {
    paint(): void;
}

interface Checkbox {
    paint(): void;
}

// Concrete Products (Windows)
class WinButton implements Button {
    paint() { console.log("Rendering Windows Button"); }
}
class WinCheckbox implements Checkbox {
    paint() { console.log("Rendering Windows Checkbox"); }
}

// Concrete Products (Mac)
class MacButton implements Button {
    paint() { console.log("Rendering Mac Button"); }
}
class MacCheckbox implements Checkbox {
    paint() { console.log("Rendering Mac Checkbox"); }
}

// Abstract Factory
interface GUIFactory {
    createButton(): Button;
    createCheckbox(): Checkbox;
}

// Concrete Factories
class WinFactory implements GUIFactory {
    createButton(): Button { return new WinButton(); }
    createCheckbox(): Checkbox { return new WinCheckbox(); }
}

class MacFactory implements GUIFactory {
    createButton(): Button { return new MacButton(); }
    createCheckbox(): Checkbox { return new MacCheckbox(); }
}

// Client Code
function createUI(factory: GUIFactory) {
    const button = factory.createButton();
    const checkbox = factory.createCheckbox();

    button.paint();
    checkbox.paint();
}

// Usage
createUI(new WinFactory()); // Output: Rendering Windows Button, Rendering Windows Checkbox
createUI(new MacFactory()); // Output: Rendering Mac Button, Rendering Mac Checkbox

4. Pros and Cons

Pros Cons
Consistency: Ensures that products you use together match each other (same variant). Complexity: Introduces a lot of new interfaces and classes.
Decoupling: Client code is not coupled to concrete product classes. Rigidity: Adding a new product type (e.g., "Table") to the family requires changing the Abstract Factory interface and all concrete factories.
SRP: Creation code is centralized in one place.

programming/design-patterns programming/object-oriented-programming programming/factory-method-pattern