Skip to content
aipatterns.dev

Guide

Factory Comparison

Tell apart a factory function, static creation method, simple factory, Factory Method and Abstract Factory, and pick the smallest one that fits.

Also known as
Simple Factory, Static factory method, Creation method

Why the word is confusing

"Factory" is used for at least five different things. Only two of them are GoF patterns. Pick by asking who decides which concrete class to create, and whether several products must match.

The five meanings

1. Factory function or creation method

Any function or method that creates and returns an object. It replaces a direct new so construction can have a descriptive name or hide setup.

TypeScript
class Money {
  private constructor(readonly cents: number, readonly currency: string) {}
  static fromDecimal(amount: number, currency: string): Money {
    return new Money(Math.round(amount * 100), currency);
  }
  static zero(currency: string): Money {
    return new Money(0, currency);
  }
}

This is not a design pattern in the catalog; it is good practice. The refactoring that introduces it is Replace Constructor with Factory Method.

2. Static factory that picks a subtype

A creation method that returns one of several implementations based on an argument.

TypeScript
interface Notifier { send(to: string, body: string): Promise<void> }

function createNotifier(channel: "email" | "sms" | "push"): Notifier {
  switch (channel) {
    case "email": return new EmailNotifier();
    case "sms":   return new SmsNotifier();
    case "push":  return new PushNotifier();
  }
}

Often called a "simple factory". The switch lives in one place, so callers stay free of it. This covers most real needs. Adding a channel means editing this function, which is fine when it is the only place that knows about channels.

3. Simple factory class

The same idea as a class with one creation method, often so it can be injected or configured. Use it when the factory needs dependencies (API keys, a clock, a logger) that callers shouldn't see.

4. Factory Method (GoF)

A base class or framework defines a workflow and calls an overridable creation method. Subclasses, or injected functions, decide the concrete product. The point is that the code calling the factory is written before the product types are known.

TypeScript
abstract class ReportJob {
  run(rows: Row[]): string {
    const writer = this.createWriter(); // the factory method
    rows.forEach((r) => writer.write(r));
    return writer.finish();
  }
  protected abstract createWriter(): RowWriter;
}

class CsvReportJob extends ReportJob {
  protected createWriter(): RowWriter { return new CsvWriter(); }
}

See Factory Method. In TypeScript you can often pass () => RowWriter into the constructor instead of subclassing.

5. Abstract Factory (GoF)

An object that creates a family of related products that must be used together. Swapping the factory swaps the whole family consistently.

TypeScript
interface StorageKit {
  blobStore(): BlobStore;
  queue(): Queue;
  lock(): DistributedLock;
}

class AwsKit implements StorageKit { /* S3, SQS, DynamoDB lock */ }
class LocalKit implements StorageKit { /* filesystem, in-memory queue, mutex */ }

function startWorker(kit: StorageKit) {
  const blobs = kit.blobStore();
  const jobs = kit.queue();
  // blobs and jobs are guaranteed to come from the same environment
}

See Abstract Factory.

Comparison table

VariantWho decides the concrete typeProductsExtend by
Creation methodThe method itself (always one type)OneAdding a named method
Simple factoryA switch or map inside the factoryOne, of several typesEditing the factory
Factory MethodA subclass or injected functionOne, used by a workflowAdding a subclass or function
Abstract FactoryThe chosen factory objectSeveral related onesAdding a whole new factory
Diagram source (Mermaid)
flowchart TD
  A[Need to create an object] --> B{More than one concrete type?}
  B -- No --> C[Creation method or plain constructor]
  B -- Yes --> D{Several products that must match?}
  D -- Yes --> E[Abstract Factory]
  D -- No --> F{Does a workflow call creation before types are known?}
  F -- Yes --> G[Factory Method]
  F -- No --> H[Simple factory function]

How to choose

  • Start with a constructor. Move to a creation method when construction needs a name, validation or caching.
  • Use a simple factory function when callers must not know concrete types, and selection is a lookup.
  • Use Factory Method when a reusable workflow, framework hook or base class needs to create something that extensions customize.
  • Use Abstract Factory only when mixing products from different families is a real bug risk.
  • If the problem is many optional parameters, not which type to create, you want Builder.
  • If new objects should copy a configured template, you want Prototype.

Common mistakes

  • Creating an XFactory class for every class with a plain constructor. That is Speculative Generality.
  • Building an Abstract Factory with one product method. That is a Factory Method or a simple factory with extra types.
  • Subclassing only to override the factory method, in a language where passing a function works. Prefer composition.

See also

Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.