Free Interactive Course · Design Patterns

Factory Method Design Pattern

Let a subclass decide which class to instantiate — and stop editing the caller every time you add one.

Creational Patternseasya.k.a. Virtual Constructor
ShareXLinkedIn
In one sentence

Define an interface for creating an object, but let subclasses decide which concrete class to create.

01

The problem Factory Method solves

The problem

Your reporting service exports finished reports. It started with one format, so ReportJob.run() ended with new PdfExporter().export(rows) and everybody was happy.

Then finance wanted CSV. So run() grew an if. Then analytics wanted XLSX, and someone needed JSON for a webhook. Now the one method that is supposed to run a report contains a four-branch conditional about file formats, imports four exporter classes, and has to be re-tested every time a fifth arrives.

The real damage is the direction of the dependency: a high-level orchestration class knows the name of every low-level detail class in the system. Add a format, edit the orchestrator. That's backwards.

02

How the Factory Method pattern works

Move the new into a method of its own, and let subclasses override that method:

  1. The base class declares a factory method — createExporter() — that returns an interface, not a concrete class.
  2. The base class's real work (run()) calls that method and programs against the interface. It never learns which class came back.
  3. Each subclass overrides the factory method to return the concrete type it needs.
A naming trap worth knowing. Most "factory pattern" tutorials show a static ExporterFactory.create("pdf") with a switch inside. That is the Simple Factory idiom — useful, but not a GoF pattern, and it doesn't remove the conditional, it just moves it. Factory Method proper uses inheritance: the subclass is the switch. If you're being asked about this in an interview, that distinction is usually the point of the question.
ReportJob+ run()+ createExporter() ◁ abstractInvoiceJob→ PdfExporterAnalyticsJob→ CsvExporter«interface» Exporter+ export(rows)returnsPdfExporterCsvExporterrun() depends on the interface · only the subclass names a concrete class
Participants. Creator (ReportJob) declares the factory method and uses whatever it returns. Concrete Creators override it. Product (Exporter) is the interface the creator programs against, and Concrete Products implement it. The arrow that matters is the one that isn't there: nothing points from ReportJob to PdfExporter.
03

See it: adding a format without touching the caller

Send a few reports, then press Add a new export format. Watch the counter that says how many edits ReportJob.run() needed.

▶ Try it — add a format, edit nothing

An interactive dispatch board: each report job type selects its own exporter, and adding a brand-new export format requires zero edits to the ReportJob.run() method that uses it.

That zero is the whole pattern. It is the Open/Closed Principle in one number: the system is open to new export formats and closed to modification of the code that consumes them.
04

Factory Method code examples

A report job whose subclasses choose their own exporter.

interface Exporter {
    void export(List<Row> rows);
}

public abstract class ReportJob {

    // The factory method. Abstract, so every subclass must answer it.
    protected abstract Exporter createExporter();

    // The real work. Note what isn't here: any concrete exporter class.
    public final void run() {
        List<Row> rows = query();
        createExporter().export(rows);
    }

    protected abstract List<Row> query();
}

public class InvoiceJob extends ReportJob {
    @Override protected Exporter createExporter() { return new PdfExporter(); }
    @Override protected List<Row> query() { return invoiceRepo.unpaid(); }
}

public class AnalyticsJob extends ReportJob {
    @Override protected Exporter createExporter() { return new CsvExporter(); }
    @Override protected List<Row> query() { return events.lastWeek(); }
}

// Adding XlsxExporter means adding one subclass. ReportJob.run() is untouched.
Read across the tabs: Java, C# and C++ express this with inheritance because that is what their type systems reward. Go has no inheritance at all, so the factory becomes a function field — and once you see that, it becomes obvious that the JavaScript and Python versions were only ever using classes out of habit. The pattern is "defer the choice of concrete type to someone else"; the subclass is one way to say that, not the definition.
05

How to implement Factory Method

  1. Find the new that varies. It is usually inside a method that also does something useful and shouldn't have to care.
  2. Define a product interface covering what the caller actually uses. Keep it small — the caller only needs export(), not the PDF library's whole surface.
  3. Add a factory method to the creator that returns that interface. Make it abstract if every subclass must answer, or give it a sensible default if most won't.
  4. Replace the new in the caller with a call to the factory method.
  5. Create one concrete creator per variant, each overriding the factory method.
  6. If you're in a language with first-class functions, check whether passing the factory in as a function is simpler than subclassing. Usually it is.
06

When to use Factory Method — and when not to

Use it when a class must create objects whose exact type it can't and shouldn't know: a framework instantiating user-supplied types, a library that must not depend on the application's classes, or a class where adding a variant currently means editing a conditional.

Where it goes wrong

One subclass per product, forever. Two products is fine. Twelve products means twelve creator subclasses that each contain a single return new X() — a whole class hierarchy carrying one line of information. At that point a map from key to constructor is honest and this is ceremony.

Applied before there is a second variant. A factory method with exactly one implementation is an indirection with no payoff. Wait for the second format; it costs less to introduce the pattern then than to maintain it in the meantime.

Confused with Simple Factory in review. If your "factory method" is a static method containing a switch, you have centralised the conditional, not removed it — adding a variant still edits that switch. That may be exactly what you want; just don't expect Open/Closed from it.

You have…Reach forWhy
One product type that will never varyJust new itIndirection with nothing behind it is a cost with no benefit.
A handful of variants chosen by a runtime stringSimple Factory or a map of constructorsHonest, compact, and the lookup table is easy to read. Not GoF, still right.
A creator that also has behaviour worth inheritingFactory MethodThe subclass carries both the choice and the specialised behaviour.
Several products that must be consistent with each otherAbstract FactoryOne factory returning a whole matched family, rather than one product.
A first-class-function language and no shared behaviourPass the constructor inSame decoupling, no hierarchy.
07

Quick check

🧠 Quick check
A colleague writes static Exporter create(String fmt) { switch (fmt) { case "pdf": … } } and calls it the Factory Method pattern. What's the most useful correction?

In the wild

JavaCollection.iterator() — every collection is a creator whose factory method returns an Iterator the caller uses without knowing its class.
Python__init_subclass__-based plugin registries, and logging.Handler subclasses selected by config rather than by the code that logs.
C#DbProviderFactory.CreateConnection() — ADO.NET's provider model is Factory Method almost verbatim.
JavaScriptdocument.createElement(tag) returns a different concrete element class per tag, behind one Element contract.
Gosql.Open(driverName, dsn) — the registered driver decides the concrete connection type; your code only sees *sql.DB.
C++std::make_unique<T> wrapped in a virtual creator is the standard shape for plugin loading in C++ frameworks.

Frequently asked questions

What is the difference between Factory Method and Abstract Factory?
Factory Method produces one product and does it through inheritance — a subclass overrides the creation method. Abstract Factory produces a family of related products and does it through composition — you hold a factory object and ask it for each member of the family. The rule of thumb: if your concern is "which class do I instantiate here", that's Factory Method. If it's "these three objects must all come from the same set or they'll break", that's Abstract Factory.
Is Simple Factory the same as Factory Method?
No, and this is the most common mix-up. Simple Factory is a static method with a conditional inside that returns one of several concrete types. It's a legitimate, useful idiom — but it isn't in the Gang of Four book, and adding a variant means editing its conditional. Factory Method uses inheritance, so adding a variant adds a subclass and edits nothing.
Do I still need Factory Method with dependency injection?
Often not. A DI container that resolves IExporter for you solves the same coupling problem by configuration instead of by subclassing. Factory Method still earns its place when the decision has to be made at runtime per call (the format depends on the request), when the creator has other behaviour that subclasses genuinely share, or when you're writing a library that can't assume a container exists.
Why not just use a map from string to constructor?
Frequently you should — it's compact, readable, and easy to extend at the registration site. Prefer the classic Factory Method when the creator has meaningful behaviour of its own that varies alongside the product, or when the language has no convenient way to store a constructor as a value. A map is the better default in Python, JavaScript, TypeScript and Go.

Finish the handbook, earn the certificate

All 23 Gang-of-Four patterns, each with a simulator you can click and code in seven languages. Free, no signup.

See all 23 patterns →
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.