Home › Low-Level Design › Factory Method Pattern
F

Factory Method Pattern

It hands the "which class do I build" decision to a subclass, so the code that uses the object never has to know.

Low-Level DesignMedium10 min read

I have watched a lot of candidates reach for this one and fumble it, almost always because they confuse it with Simple Factory or Abstract Factory. In a 45-minute LLD loop that mix-up quietly moves a "hire" to a "no hire": it says you memorized names but never shipped the pattern. Let me draw it the way I would on a whiteboard.

If you remember five things

The whole pattern in one glance. Everything below defends these five calls.

  1. Intent. A base class owns a stable flow and calls a creation method it declares but does not implement, so each subclass decides the concrete product.
  2. The Creator is the star, not the factory. The overridable method is a small piece inside a larger method that actually uses the product. No surrounding logic means no pattern.
  3. It is Dependency Inversion in code. High-level policy depends on the Product interface, and the concrete choice gets pushed down into the subclass.
  4. The if does not vanish, it moves. The branch leaves your business logic and lives in one small spot at the edge that only picks a creator.
  5. The classic gotcha. People call Simple Factory (a static switch) "Factory Method," or add three classes to dodge a two-branch if. Both fail the bar.

1The problem it solves#

This situation shows up constantly. Name it fast and the pattern sells itself.

  • You are writing logic that creates an object, does work with it, and returns a result.
  • The work is the same every time.
  • The type of object you create changes with context.

A logistics app makes it concrete. The flow is identical: take an order, plan a delivery, dispatch it. Some orders ship by truck, some by drone. The naive version:

public String planDelivery(String mode) {
    Transport t;
    if (mode.equals("truck")) {
        t = new Truck();
    } else if (mode.equals("drone")) {
        t = new Drone();
    } else {
        throw new IllegalArgumentException("unknown mode");
    }
    return t.deliver();
}

This works until it does not. Each symptom is a separate reason the design rots:

  • Every new shipping mode means cracking open this method and bolting on another else if.
  • Six modes later it is a 40-line conditional that every engineer is scared to touch.
  • The method knows about every concrete class in the system. new Truck() is welded into the business logic.
  • You cannot unit test the planning logic without dragging real transport classes along: a test that should run in 2ms now spins up a truck object.
  • You keep editing a method that, conceptually, you finished months ago.
The one-line diagnosis

The thing changing is the creation step. Everything around it is stable. That exact mismatch, a stable flow wrapped around a varying "what do I build," is what Factory Method is built for. Say that sentence out loud in the room and you have already earned the next three minutes.

2The idea (mental model)#

Here is how I hold it in my head.

  • Declare a creation method, leave it empty in the base class, and let each subclass decide what to build.
  • The base class writes the recipe. It calls its own createTransport() in the middle of its logic.
  • It does not know, and does not care, what that method returns.
  • TruckLogistics overrides createTransport() to return a Truck. DroneLogistics returns a Drone.
  • The recipe never changes. Only the one creation step swaps per subclass.

The trick that makes it click:

  • The base class calls a method it declares but does not implement.
  • The subclass supplies the "what." The base class owns the "when" and "how it gets used."
  • That inversion is the whole pattern, and it is a textbook Dependency Inversion case: high-level policy (the delivery recipe) depends on an abstraction (Transport), and the low-level detail (which concrete transport) is pushed down into the subclass.

Keep the three cousins separate and you will never trip in an interview:

  • Simple Factory: a static method with a switch inside. Not really a pattern, more a coding habit.
  • Abstract Factory: creates families of related objects.
  • Factory Method: one product, one virtual creation method, decided by subclass.

The factory is not the main character. The Creator is.

3Structure#

Four roles. Learn them as a cast, not a diagram.

  • Product interface: the type your business logic talks to (Transport).
  • ConcreteProduct: the real things (Truck, Drone).
  • Creator: the abstract class that holds your logic and declares the factory method (Logistics).
  • ConcreteCreator: subclasses that override the factory method to return a specific product.

Why the Creator is the star:

  • People think the "factory" is the main character.
  • The Creator usually has a real method with real logic that uses the product.
  • The factory method is a small, overridable piece inside a larger stable flow.
classDiagram class Transport { <> +deliver() String } class Truck { +deliver() String } class Drone { +deliver() String } class Logistics { <> +planDelivery() String +createTransport()* Transport } class TruckLogistics { +createTransport() Transport } class DroneLogistics { +createTransport() Transport } Transport <|.. Truck Transport <|.. Drone Logistics <|-- TruckLogistics Logistics <|-- DroneLogistics Logistics ..> Transport
Read it top to bottom. Truck and Drone implement Transport. TruckLogistics and DroneLogistics extend Logistics. Watch the Logistics ..> Transport arrow: it points at the interface, never at Truck or Drone. That arrow is the payoff, and pointing at it in the room proves you understand the decoupling.

4Implementation in Java#

// Product
interface Transport {
    String deliver();
}

// Concrete products
class Truck implements Transport {
    public String deliver() {
        return "Delivering by road in a box.";
    }
}

class Drone implements Transport {
    public String deliver() {
        return "Delivering by air to the doorstep.";
    }
}

// Creator: holds the real logic, declares the factory method
abstract class Logistics {

    // the factory method, subclasses decide what to build
    protected abstract Transport createTransport();

    // the stable business logic, written once, never touched again
    public String planDelivery() {
        Transport t = createTransport();
        String route = "Route planned. ";
        return route + t.deliver();
    }
}

// Concrete creators
class TruckLogistics extends Logistics {
    protected Transport createTransport() {
        return new Truck();
    }
}

class DroneLogistics extends Logistics {
    protected Transport createTransport() {
        return new Drone();
    }
}

Using it:

public class Demo {
    public static void main(String[] args) {
        Logistics logistics = pickLogistics("drone");
        System.out.println(logistics.planDelivery());
    }

    static Logistics pickLogistics(String region) {
        // one place decides which creator, usually config or input
        if (region.equals("drone")) return new DroneLogistics();
        return new TruckLogistics();
    }
}

Notice what happened to the if. It did not vanish. It moved.

  • It left planDelivery where it corrupts your core logic.
  • It now lives in one small spot at the edge that only chooses which creator to instantiate.
  • planDelivery is closed to modification.
  • Add a ShipLogistics tomorrow and you touch exactly two spots: a new three-line subclass, and the one branch in pickLogistics.
  • planDelivery never gets opened again. That is the Open/Closed Principle actually doing something, not just a slogan.

5A real-world example#

You have used this pattern a hundred times without naming it.

  • Collection.iterator() is a factory method: ArrayList returns an array-backed iterator, LinkedList returns a node-walking one, and your for-each loop never knows the difference.
  • Calendar.getInstance() hands back a locale-appropriate concrete calendar.
  • Both are "I call a method to get an object and I do not control which concrete class comes back."

In a real LLD loop it shows up as a document editor.

  • The Application class has an openDocument() flow: check permissions, load bytes, render.
  • A DrawingApp creates DrawingDocument objects, a TextApp creates TextDocument objects.
  • Rather than branching inside openDocument, each app subclass overrides createDocument().
  • The open flow is written once in the base Application.
  • This is the exact example from the Gang of Four book, so naming it signals you know the source, not just a blog summary.

Another one I like: a notification system.

  • Base NotificationService has send(message) that logs, rate-limits, and dispatches.
  • Subclasses override createChannel() to return an EmailChannel, SmsChannel, or PushChannel.
  • The rate-limiting and logging code gets written exactly once and inherited by all three.

Here is the runtime flow for the logistics example, since the order of calls is what people miss:

sequenceDiagram participant Client participant DroneLogistics participant Drone Client->>DroneLogistics: planDelivery() DroneLogistics->>DroneLogistics: createTransport() DroneLogistics->>Drone: new Drone() DroneLogistics->>Drone: deliver() Drone-->>DroneLogistics: "Delivering by air..." DroneLogistics-->>Client: "Route planned. Delivering by air..."
The client calls planDelivery, which lives in the base class but runs on the subclass instance. The overridden createTransport fires inside it: that is polymorphism carrying the creation decision. The client is two steps removed from new Drone() and never sees it.

6When to use it, and when not to#

Pause before the list: what is the single test that tells you this pattern belongs here, not a plain function?
Reveal the answer
Is there meaningful shared logic in the Creator that *uses* the product? If the Creator has a real flow wrapped around the creation call (route planning, rate limiting, permission checks), Factory Method earns its keep. If `planDelivery` would just return `createTransport().deliver()` with nothing around it, you added three classes for nothing and you need a function.

Reach for Factory Method when:

  • You have a stable algorithm that creates and uses an object, and the type of that object varies by subclass or context.
  • You want users of a framework to plug in their own product types without you rewriting the core flow. This is why frameworks love it: Spring, JUnit, and the servlet spec all lean on it.
  • The creation logic is genuinely subject to change and you want it isolated behind one overridable method.

Leave it on the shelf when:

  • You only ever create one type of object. Then new Thing() is correct and a factory is theater.
  • The decision is a simple one-time switch with no shared surrounding logic. A plain static factory method, or a Map of suppliers, is lighter and honest about what it is.
  • You would be creating an abstract class and two subclasses purely to avoid a two-branch if. That is more classes, not better design.
From the interviewer's chair

I have rejected plenty of over-engineered solutions that reached for this pattern to dodge a trivial conditional. When a candidate says "this is only one type, so I will use a constructor," I lean in. Restraint reads as more senior than pattern recall every single time.

7Common mistakes#

The ones that actually come up, in the order they cost you.

  • Calling Simple Factory "Factory Method." A static method with a switch is not this pattern. Factory Method uses subclassing and overriding. Miss this and I catch it in the first two minutes.
  • Putting no logic in the Creator. If planDelivery just returns createTransport().deliver() with nothing around it, you added three classes for nothing. The Creator earns its keep through the stable logic that surrounds the creation call.
  • Making the factory method public and treating it as the API. The product of the pattern is usually the business method (planDelivery), not createTransport. Keep the factory method protected. Clients talk to the real behavior, not the creation hook.
  • Confusing it with Abstract Factory. Factory Method: one product, decided by subclass, via method override. Abstract Factory: a family of products, usually composed in as an object you hold. Different shapes, different problems.
  • Subclass explosion. Ten creator subclasses that each differ by one line means the variation belongs in data, not in types. Reach for a registry of suppliers, a Map<String, Supplier<Transport>>, instead.
Red flag that fails you here

Drawing the four classes correctly, then being unable to answer "why not just a static factory with a switch?" If you cannot name the shared Creator logic that makes subclassing worth it, you have shown me a pattern you memorized, not one you have shipped. The decoupling has to buy you something concrete.

8Where it shows up in interviews#

LLD interviewers plant this everywhere.

  • Design a logging framework, a payment processor, a ride-matching service, a maze game with different room types.
  • The trigger phrase: "the system should support adding new types of X later without changing existing code."
  • That is your cue to name Factory Method and show the Creator holding the stable flow.

Two moves score points.

  • Say out loud why you are not just using new: "I want the creation decision isolated so the open flow stays closed to modification." Interviewers want the reasoning, not the recital.
  • Draw the four roles fast and point at the dependency arrow from Creator to the Product interface. That one arrow proves you understand the decoupling, which is the entire point.

And if the problem genuinely needs one object type, say so and use a constructor. Knowing when not to apply a pattern is the staff-bar signal.

Follow-ups the interviewer will ask (and your answers)
"How is this different from Simple Factory?"
Simple Factory is one static method with a switch inside, picking a concrete class by argument. It is a coding habit, not a GoF pattern, and the switch still centralizes knowledge of every concrete type. Factory Method uses subclassing: the base class declares an abstract creation method and each subclass overrides it, so adding a type is a new subclass, not an edit to an existing switch.
"And Abstract Factory? People use the names interchangeably."
Different shapes. Factory Method is one product decided by a subclass overriding one virtual method. Abstract Factory creates a whole *family* of related products (think a GUI toolkit making matching buttons, menus, and scrollbars for one theme), and it is usually an object you compose in, not a subclass you extend. One method override versus one object held.
"When would you NOT use Factory Method and just write a function?"
When there is no meaningful shared logic in the Creator that uses the product, or when it is a one-time switch with nothing around it. If the Creator method would just be `return createTransport().deliver()`, the three extra classes buy nothing. A plain static factory or a `Map>` is lighter and honest. Creating an abstract class plus two subclasses to dodge a two-branch if is over-engineering.
"You have ten subclasses that each differ by one line. Smell?"
Yes, subclass explosion. When the only variation is which concrete class gets newed, that variation is data, not type. Replace the subclasses with a registry: a `Map>` keyed by mode, injected into one Creator. Adding a type becomes a map entry, not a class.
"Where does this already live in the JDK or a framework?"
`Collection.iterator()` is the cleanest example: `ArrayList` and `LinkedList` each return their own iterator and the caller never knows which. `Calendar.getInstance()` returns a locale-appropriate calendar. Frameworks like Spring, JUnit, and the servlet spec use it so you can plug in product types without them rewriting their core flow.

What you can now explain in the room

  • The exact problem it fixes: a stable flow wrapped around a varying creation step.
  • Why the Creator, not the factory method, is the main character of the pattern.
  • How it is Dependency Inversion and Open/Closed doing real work, not slogans.
  • The clean Java shape: abstract Creator, protected factory method, concrete creators, and the branch that moved to the edge.
  • How to tell Factory Method, Simple Factory, and Abstract Factory apart in one sentence each.
  • When to refuse the pattern: one product type, a trivial switch, or variation that belongs in a supplier map.

Next, look at Abstract Factory for creating product families, and the Strategy pattern, which also injects behavior but through composition rather than subclass overriding.

Get a prep plan built around your Factory Method Pattern interview

Tell us the role and your interview date. We will send back a dated, day by day plan. Free.

Thanks. Check your inbox, your Factory Method Pattern prep plan is on the way.