Back to Design Patterns
Creational Pattern

Abstract Factory Pattern

Provide an interface for creating families of related objects without specifying their concrete classes — ensuring products from the same family are always used together.

Intermediate11 min read

What is the Abstract Factory Pattern?

The Abstract Factory pattern is a creational design pattern that lets you create families of related objects through a single interface — without specifying the concrete classes of the objects you're creating.

Think of it as a furniture showroom: you pick a style (Modern, Victorian, Art Deco). Each style gives you a matching sofa, chair, and table. You'd never mix a Victorian sofa with a Modern chair — the factory ensures every product belongs to the same family.

Key Idea: Create families of related objects through one interface. Swap the entire family by swapping the factory.

Abstract Factory vs Factory Method

AspectAbstract FactoryFactory Method
CreatesA family of related objectsOne type of object
ConsistencyProducts guaranteed compatibleNo such guarantee
MechanismCompositionInheritance

Core Participants

Abstract Factory

Abstract Factory Interface

Declares creation methods for each distinct product type in the family.

Concrete Factory

Concrete Factory

Implements the abstract factory interface for a specific product family.

Abstract Product

Abstract Product

Interface for each distinct type of product (Button, Checkbox, etc).

Concrete Product

Concrete Product

The real objects created by a concrete factory.

!Problem It Solves

Incompatible Product Families

// Without Abstract Factory — risky mismatch
Button btn = new WindowsButton();
Checkbox cb = new MacCheckbox(); // OOPS! Mixed families.

Solution With Abstract Factory

// Factory guarantees consistency
UIComponentFactory factory = new WindowsUIFactory();
Button btn = factory.createButton(); // Guaranteed Windows

Implementation

// Abstract Factory Pattern — Cross-Platform UI Components

// ─── Abstract Products ────────────────────────────────────────
interface Button {
    void render();
    void onClick();
}

interface Checkbox {
    void render();
    void toggle();
}

interface TextInput {
    void render();
    String getValue();
}

// ─── Concrete Products: Windows ───────────────────────────────
class WindowsButton implements Button {
    public void render()  { System.out.println("[Windows] Rendering flat button with accent color"); }
    public void onClick() { System.out.println("[Windows] Button click — ripple effect"); }
}

class WindowsCheckbox implements Checkbox {
    public void render()  { System.out.println("[Windows] Rendering square checkbox"); }
    public void toggle()  { System.out.println("[Windows] Checkbox toggled — checkmark animates"); }
}

class WindowsTextInput implements TextInput {
    public void render()     { System.out.println("[Windows] Rendering underline text field"); }
    public String getValue() { return "Windows input value"; }
}

// ─── Concrete Products: macOS ─────────────────────────────────
class MacButton implements Button {
    public void render()  { System.out.println("[macOS] Rendering pill-shaped button"); }
    public void onClick() { System.out.println("[macOS] Button click — subtle shadow"); }
}

class MacCheckbox implements Checkbox {
    public void render()  { System.out.println("[macOS] Rendering rounded checkbox"); }
    public void toggle()  { System.out.println("[macOS] Checkbox toggled — smooth slide"); }
}

class MacTextInput implements TextInput {
    public void render()     { System.out.println("[macOS] Rendering rounded bordered field"); }
    public String getValue() { return "macOS input value"; }
}

// ─── Abstract Factory ─────────────────────────────────────────
interface UIComponentFactory {
    Button createButton();
    Checkbox createCheckbox();
    TextInput createTextInput();
}

// ─── Concrete Factories ───────────────────────────────────────
class WindowsUIFactory implements UIComponentFactory {
    public Button    createButton()    { return new WindowsButton(); }
    public Checkbox  createCheckbox()  { return new WindowsCheckbox(); }
    public TextInput createTextInput() { return new WindowsTextInput(); }
}

class MacUIFactory implements UIComponentFactory {
    public Button    createButton()    { return new MacButton(); }
    public Checkbox  createCheckbox()  { return new MacCheckbox(); }
    public TextInput createTextInput() { return new MacTextInput(); }
}

// ─── Client — uses factory without knowing concrete types ──────
class LoginForm {
    private Button submitBtn;
    private Checkbox rememberMe;
    private TextInput emailInput;

    public LoginForm(UIComponentFactory factory) {
        submitBtn  = factory.createButton();
        rememberMe = factory.createCheckbox();
        emailInput = factory.createTextInput();
    }

    public void render() {
        System.out.println("\n--- Rendering Login Form ---");
        emailInput.render();
        rememberMe.render();
        submitBtn.render();
    }

    public void submit() {
        submitBtn.onClick();
        System.out.println("Email: " + emailInput.getValue());
    }
}

// ─── Entry point ──────────────────────────────────────────────
public class App {
    public static void main(String[] args) {
        String os = System.getProperty("os.name").toLowerCase();

        UIComponentFactory factory = os.contains("mac")
            ? new MacUIFactory()
            : new WindowsUIFactory();

        LoginForm form = new LoginForm(factory);
        form.render();
        form.submit();
        // All components are guaranteed to match the same platform!
    }
}

When to Use Abstract Factory

Cross-Platform UI Toolkits

When your app must run on multiple platforms and each needs its own matching look-and-feel.

WindowsUIFactory, MacUIFactory

Multi-Environment Infrastructure

When switching environments should swap the entire family (DB, Cache, Queue) together.

LocalDevFactory, AWSFactory

Theme / Skin Systems

When the entire UI must switch coherently between themes.

LightThemeFactory, DarkThemeFactory

Pros & Cons

Advantages

  • Products are guaranteed compatible.
  • Client code is decoupled from concrete classes.

Disadvantages

  • Adding a new product type requires changing all factories.
  • Initial code complexity is higher.

Real-World Examples

Java AWT / Swing Look and Feel

Calling UIManager.setLookAndFeel() swaps the factory — all components re-render in the new style.

Doctrine DBAL (PHP)

Creates platform-specific query builders matched to the connected database vendor.

React Native StyleSheet

Platform-specific rendering produces iOS UIKit views or Android View objects depending on the factory.

What's Next?

Explore other Creational patterns: