Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Factory Method
LLD

Factory Method

Understand how subclasses or implementations can decide which concrete object gets created.

Factory Method

Intent

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method defers instantiation to subclasses — the difference from simple factory is who decides: not a central switch, but each concrete creator subclass overriding one method.

The Problem Shape It Fits

A framework provides the workflow; applications provide the products. A dialog framework knows how to render a window with one button inside — but which button (Windows-styled, HTML, dark-mode)? The framework cannot hardcode it and cannot know all future button types. So it declares: “my code calls createButton(); whoever extends me implements that.”

 CREATOR HIERARCHY                    PRODUCT HIERARCHY

 ┌──────────────────────┐             ┌──────────────┐
 │ «abstract» Dialog    │   creates   │ «interface»  │
 │ + render()           │────────────►│ Button       │
 │ # createButton() ◄───┼── declared  └──────△───────┘
 └──────────▲───────────┘  abstract            │
            │ overrides                        ├── WinButton
   ┌────────┴─────────┐                        ├── HtmlButton
   │ WindowsDialog    │──── returns ───────────┤
   │  createButton()  │        new WinButton() ┆
   ├──────────────────┤                        ┆
   │ HtmlDialog       │──── new HtmlButton()   ┆
   └──────────────────┘                        ┆

The Dialog.render() skeleton calls its own abstract createButton() — a template method over creation. Subclasses never touch rendering logic; they only answer “what button?”

Mechanics

abstract class Dialog {
    public void render() {              // fixed workflow — closed for modification
        Button b = createButton();      // ← the factory method hook
        b.onClick(() -> close());
        display(b);
    }
    protected abstract Button createButton();   // open for extension
}

class HtmlDialog extends Dialog {
    @Override protected Button createButton() { return new HtmlButton(); }
}

Structure Roles

RoleJob
Product (Button)Interface all products satisfy
Creator (Dialog)Declares factory method; uses product in business methods
Concrete creatorOverrides factory, returns its product
Concrete productThe actual class constructed

Simple Factory vs Factory Method

Simple factoryFactory method
Decision locationOne switch in one classDistributed across subclasses
Adding a variantEdit the switchNew subclass pair, zero edits
Inheritance involvedNoYes
FitsClosed variant setsFrameworks, plugin extension

Real-World Sightings

  • Calendar.getInstance() — locale decides the concrete calendar class.
  • java.nio.charset.Charset.forName / SLF4J LoggerFactory.getLogger — environment/config picks implementations.
  • JUnit’s runner discovery — framework asks, subclass/test answers.

Interview Framing

  • The scoring sentence: “factory method is OCP applied to creation — the switch dissolves into the type system.”
  • Follow-up trap: “why not just pass a Supplier<Button>?” — valid modern alternative (composition instead of inheritance); knowing when either fits shows judgment.

The Scenario

A logistics app delivers by land and sea. Requirements grow quarterly (“add air freight, then drones”). The design must make each addition a new file, never an edit to delivery logic.

Full Implementation

// ---------- PRODUCT HIERARCHY ----------
interface Transport {
    String deliver(String cargo);
}

class Truck implements Transport {
    @Override public String deliver(String cargo) {
        return "Truck: " + cargo + " via highway";
    }
}

class Ship implements Transport {
    @Override public String deliver(String cargo) {
        return "Ship: " + cargo + " via sea lane";
    }
}

// ---------- CREATOR HIERARCHY ----------
abstract class LogisticsManager {
    // template method — the stable workflow (closed)
    public final String planDelivery(String cargo) {
        Transport t = createTransport();          // ← factory method hook
        return t.deliver(cargo);
    }
    protected abstract Transport createTransport();   // open for extension
}

class RoadLogistics extends LogisticsManager {
    @Override protected Transport createTransport() { return new Truck(); }
}

class SeaLogistics extends LogisticsManager {
    @Override protected Transport createTransport() { return new Ship(); }
}

The Extension Proof

Air freight arrives next quarter:

class Plane implements Transport {
    @Override public String deliver(String cargo) {
        return "Plane: " + cargo + " via air";
    }
}
class AirLogistics extends LogisticsManager {
    @Override protected Transport createTransport() { return new Plane(); }
}

planDelivery, Truck, Ship — all untouched. Diff = two new files. That is OCP on creation, demonstrated.

The Testing Seam

class FakeTransport implements Transport {
    @Override public String deliver(String cargo) { return "FAKE-OK"; }
}
class TestLogistics extends LogisticsManager {
    @Override protected Transport createTransport() { return new FakeTransport(); }
}
// planDelivery now testable without any real transport side effects

The same hook that enables products enables fakes — creation points are always test seams.

Client Usage

Map<String, LogisticsManager> managers = Map.of(
    "road", new RoadLogistics(),
    "sea",  new SeaLogistics());
managers.get(config.mode()).planDelivery("laptops");

One configuration line selects an entire behavior family.

Production Notes

  • Constructors needing runtime data (API keys, region)? Pass through creator constructors — creators are normal objects.
  • Expensive products? Creator can memoize (if (transport == null) transport = create...) — caching belongs at this seam.
  • Modern alternative: LogisticsManager(Supplier<Transport> t) collapses subclasses into lambdas; prefer it when no per-family logic beyond creation exists. Factory-method inheritance earns its keep only when creators carry additional behavior.

Interview Framing

  • Being asked to implement it in 10 minutes is common; delivering product+creator hierarchies plus the fake-for-tests closes all rubric axes.
  • Mentioning the Supplier simplification signals current-practice awareness without dismissing the classic form.

My Private Notes

Notes are auto-saved locally to this device.