Factory Method: Move Creation Behind a Decision

Factory Method separates object creation from the workflow that uses the object, allowing a subtype or configuration to choose the concrete product.

What is the Factory Method pattern?

The Factory Method pattern is a creational design pattern that defines a method whose job is to create an object, while letting subclasses or configuration decide which concrete class gets instantiated. The calling workflow asks its creator for "a product that satisfies this interface" and never touches a concrete constructor itself.

The pattern matters because `new` is a hard dependency. Every workflow that writes `new PdfRenderer()` is welded to that class forever. Moving creation behind a factory method gives the codebase one seam where the product decision lives — which is also exactly where tests inject fakes and where new product types get registered.

The logic, step by step

Problem

Business logic repeatedly constructs concrete classes, so changing a product type forces edits across unrelated workflows.

Rule

Define a creation method that returns a shared product contract and let specialized creators choose the concrete result.

Run
  1. WORKFLOW asks its factory method for a compatible product.
  2. CREATOR selects and constructs the concrete implementation needed.
  3. WORKFLOW uses only the shared contract after creation completes.
Output

Creation decisions can evolve without spreading concrete constructor knowledge through the application.

Factory Method pattern example in TypeScript

TypeScript
interface Renderer {
  render(doc: Document): Buffer;
}

abstract class ExportJob {
  // The factory method: subclasses decide the concrete product.
  protected abstract createRenderer(): Renderer;

  run(doc: Document): Buffer {
    const renderer = this.createRenderer();
    audit.log('export.started');
    const output = renderer.render(doc);   // workflow uses the contract only
    audit.log('export.finished');
    return output;
  }
}

class WebExportJob extends ExportJob {
  protected createRenderer(): Renderer { return new HtmlRenderer(); }
}

class PrintExportJob extends ExportJob {
  protected createRenderer(): Renderer { return new PdfRenderer({ dpi: 300 }); }
}

const job: ExportJob = userWantsPrint ? new PrintExportJob() : new WebExportJob();
job.run(currentDocument);
ExportJob owns the workflow (audit, render, return) and never names a concrete renderer. Adding an SVG export is one new subclass, zero edits to the pipeline.

Run it in the real world

A document export workflow requests a renderer while web, print, and mobile creators provide different renderers behind the same interface.

When to use it — and when not to

Reach for Factory Method when

  • A workflow must stay generic while the concrete object it operates on varies by platform, format, or configuration.
  • Object construction is complex or conditional and is currently duplicated across call sites.
  • You want tests to substitute the product without patching constructors.

Skip it when

  • One concrete class, simple constructor, no variation on the horizon — just call new.
  • Every new product forces a new creator subclass with nothing in it; a registry map or a simple parameterized factory function is lighter.

Template Method pattern — Factory Method is literally a Template Method whose varying step is object creation. If more steps than creation vary, you are looking at Template Method proper.

Singleton pattern — Both control instantiation, but Singleton restricts how many instances exist while Factory Method decides which class gets instantiated.

Frequently asked questions

What is the difference between Factory Method and Abstract Factory?

Factory Method is one method that creates one product, usually via subclassing. Abstract Factory is an object with several factory methods that create a whole family of related products (buttons, menus, and dialogs that must match). Abstract Factory is typically composed of factory methods.

Is a static factory method the same pattern?

Not in the GoF sense. A static creator like User.fromJson() improves construction ergonomics but cannot be overridden by a subclass, so it does not defer the creation decision — which is the point of the pattern.

Why not just use dependency injection instead of Factory Method?

If the concrete product can be chosen once at wiring time, DI is simpler and usually better. Factory Method earns its place when products must be created repeatedly, on demand, with runtime data that the DI container cannot know in advance.