Design PatternsCreational

Abstract Factory

Provide an interface for creating families of related objects without specifying their concrete classes.

2 min readDesigns · LLD & Patterns

Intent

Create families of related objects together, ensuring they are compatible with each other.

The classic motivating example: a UI toolkit with consistent look-and-feel. If you pick a Mac theme, every widget — button, scrollbar, menu — should be Mac-styled. Mixing a Mac button with a Windows scrollbar is a bug.


Factory Method vs Abstract Factory

AspectFactory MethodAbstract Factory
ScaleOne productFamily of products
MechanismSubclass overrides one methodOne factory class with multiple methods
When to add a new variantNew subclassNew concrete factory class

If you need exactly one product → factory method. If you need a suite of related products → abstract factory.


Structure

StructureClass diagram

Code

// Product interfaces
public interface Button   { void render(); void click(); }
public interface Checkbox { void render(); void toggle(); }

// Concrete products — Windows family
class WindowsButton   implements Button   { public void render() {/*...*/} public void click() {} }
class WindowsCheckbox implements Checkbox { public void render() {/*...*/} public void toggle() {} }

// Concrete products — Mac family
class MacButton   implements Button   { public void render() {/*...*/} public void click() {} }
class MacCheckbox implements Checkbox { public void render() {/*...*/} public void toggle() {} }

// Abstract factory
public interface GUIFactory {
    Button createButton();
    Checkbox createCheckbox();
}

class WindowsFactory implements GUIFactory {
    public Button   createButton()   { return new WindowsButton(); }
    public Checkbox createCheckbox() { return new WindowsCheckbox(); }
}

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

Caller

public class Application {
    private final Button button;
    private final Checkbox checkbox;

    public Application(GUIFactory factory) {
        this.button = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }
}

// Wire up at startup
GUIFactory factory = isMac() ? new MacFactory() : new WindowsFactory();
Application app = new Application(factory);

The Application doesn't import any concrete MacButton or WindowsButton — it works with whatever family is injected.


When to Use

ScenarioWhy it fits
UI themesFamily = button + scrollbar + menu, all matching
Cross-database queriesFamily = Connection + Statement + ResultSet, per vendor
Cross-platform file systemFamily = Path + Watcher + Permissions, per OS
Game enemiesFamily = orc + orc-archer + orc-shaman per faction

Real-world Examples

  • JDBC: Each vendor's driver is an abstract factory producing Connection, Statement, ResultSet.
  • javax.xml.parsers.DocumentBuilderFactory: returns DocumentBuilder and related parsers.
  • AWT/Swing LookAndFeel: produces UI components matching the theme.

Trade-offs

✅ Pros:

  • Guarantees compatibility within a family
  • Caller code is decoupled from concrete classes
  • Swap whole families at runtime

❌ Cons:

  • Adding a new product type (e.g., Slider) requires changing the factory interface and every concrete factory
  • More boilerplate than factory method
  • Easy to over-apply when factory method would suffice

Interview Tips

  • Use abstract factory when the interviewer's problem mentions "two themes", "two databases", "two file formats", or any cross-cutting variation.
  • If they say "we want consistent X across the app," that's a family — abstract factory.
  • Volunteer the trade-off: easy to add a new family, hard to add a new product type.

Finished reading?

Mark it done to track your progress in Designs.