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 dynamically

Interactive Abstract Factory SimulatorLIVE PLAYGROUND

Interact with the controls below to see how this design pattern executes in memory at runtime.

Category: Creational
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

ParticipantRole & ResponsibilityType
GUIFactory (Interface)Declares createButton() and createCheckbox()interface
WinFactory / MacFactoryImplements creation for Windows or macOS componentsclass
Button / Checkbox (Interfaces)Abstract product familiesinterface
WinButton, MacButton, etc.Concrete implementationsclass
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.