Factory Method Pattern

Defer instantiation to a method subclasses override. The seam between knowing what to make and knowing how to make it.

Pattern Foundational
8 min read
pattern creational factory-method polymorphism

What it is#

The Factory Method pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. The Gang of Four called this “defer instantiation to subclasses”: the parent class knows it needs some product, the subclass knows which product.

The roles are four: a Product interface that all created objects implement; ConcreteProduct classes that implement it; a Creator class with a factoryMethod() that returns a Product; and ConcreteCreator subclasses that override factoryMethod() to return a specific kind of product. The Creator’s other methods call factoryMethod() without knowing — or caring — which concrete product comes back.

The pattern is the seam between what to make and how to make it. Code that uses a product depends on the abstract Product interface; code that constructs the product lives in one place behind the factory method. When tomorrow brings a new kind of product, you add a subclass; you do not edit the code that already works.

Class structure#

┌──────────────────────┐ ┌──────────────────┐
│ Creator │ creates │ Product │
├──────────────────────┤────────►├──────────────────┤
│ + operation() │ │ + use() │
│ # factoryMethod() │ └──────────────────┘
└──────────▲───────────┘ △
│ │
┌──────────┴───────────┐ ┌────────┴─────────┐
│ ConcreteCreatorA │ creates │ ConcreteProductA │
├──────────────────────┤────────►├──────────────────┤
│ # factoryMethod() │ │ + use() │
└──────────────────────┘ └──────────────────┘
┌──────────────────────┐ ┌──────────────────┐
│ ConcreteCreatorB │ creates │ ConcreteProductB │
├──────────────────────┤────────►├──────────────────┤
│ # factoryMethod() │ │ + use() │
└──────────────────────┘ └──────────────────┘

The # prefix marks protectedfactoryMethod() is the subclass extension point; operation() is the public method that calls it.

When to use it#

Reach for Factory Method when:

  • A class needs to create objects but cannot know their exact type at compile time — the type depends on configuration, the caller, or the input.
  • You want to localise the new calls so adding a new product type means adding a subclass, not editing twenty switch statements.
  • The creation logic itself has steps that are stable across variants — only the final concrete type changes.
  • You want subclasses to participate in object creation as part of their contract.

Concrete shapes this takes:

  • Shape factories — a drawing app’s ShapeCreator subclasses (CircleCreator, SquareCreator) each return their own Shape.
  • Payment processors — a PaymentGateway base with subclasses StripeGateway and PaypalGateway, each instantiating their own client connection.
  • Database connectors — a ConnectionFactory whose MySqlFactory / PostgresFactory subclasses construct the right Connection.
  • Document parsersDocument subclasses that each create their own kind of Parser.

When not to use it:

  • When there is only one product type today and there will only ever be one — a plain constructor is simpler.
  • When the variation is by family rather than single type — use Abstract Factory Pattern instead.
  • When the variation is in how the object is configured, not which class it is — use Builder Pattern.

How it works#

A payment-processing example. The PaymentProcessor base class runs the same workflow for every payment — validate, charge, audit — but the concrete PaymentGateway it uses depends on the subclass. Adding a new payment provider is a new subclass; the workflow code never changes.

// Product — the thing being created.
public interface PaymentGateway {
String charge(String customerId, long amountCents);
}
// Concrete products.
public final class StripeGateway implements PaymentGateway {
@Override public String charge(String customerId, long amountCents) {
// Call Stripe API; return a transaction id.
return "stripe_tx_" + System.nanoTime();
}
}
public final class PaypalGateway implements PaymentGateway {
@Override public String charge(String customerId, long amountCents) {
return "pp_tx_" + System.nanoTime();
}
}
// Creator — declares the factory method and uses it in its workflow.
public abstract class PaymentProcessor {
// The factory method. Subclasses decide which gateway to build.
protected abstract PaymentGateway createGateway();
// Template method that calls the factory method.
public final String process(String customerId, long amountCents) {
if (amountCents <= 0) throw new IllegalArgumentException("amount must be positive");
PaymentGateway gateway = createGateway();
String txId = gateway.charge(customerId, amountCents);
audit(customerId, amountCents, txId);
return txId;
}
private void audit(String customerId, long amountCents, String txId) {
System.out.println("AUDIT " + txId + " customer=" + customerId + " amount=" + amountCents);
}
}
// Concrete creators.
public final class StripeProcessor extends PaymentProcessor {
@Override protected PaymentGateway createGateway() { return new StripeGateway(); }
}
public final class PaypalProcessor extends PaymentProcessor {
@Override protected PaymentGateway createGateway() { return new PaypalGateway(); }
}
// Usage:
// PaymentProcessor p = switch (provider) {
// case "stripe" -> new StripeProcessor();
// case "paypal" -> new PaypalProcessor();
// default -> throw new IllegalArgumentException(provider);
// };
// String tx = p.process("cust_42", 1999);

Five things worth noticing:

  • The workflow lives once. process() is identical across all subclasses; only the construction step varies. This is the Factory Method working with the Template Method — they often appear together.
  • Subclasses extend by adding, not editing. Adding AdyenProcessor requires zero changes to PaymentProcessor. That is the Open-Closed Principle in action.
  • The factory method is protected. Clients call process(), not createGateway(). The factory method is an extension point, not a public API.
  • Return type is the interface. createGateway() returns PaymentGateway, not StripeGateway. The base class depends on the abstraction; subclasses choose the implementation.
  • No reflection, no registry. Plain polymorphism does the dispatching. This is what makes Factory Method simpler than a registry-based factory: it is just OOP.

Variants#

VariantMechanismWhen it fits
Classical (subclass override)Abstract method overridden by ConcreteCreator subclasses.The textbook form; useful when creation is genuinely tied to a class hierarchy.
Parameterised factory methodOne method that takes a discriminator (createShape(String type)) and returns the right product.The hierarchy of creators would be overkill; one class can switch internally.
Static factory methodpublic static T of(...) on the product class itself (e.g. List.of(...), Optional.of(...)).Replacing a public constructor; gives meaningful names and can cache.
Functional factorySupplier<Product> passed in instead of subclassing.Java 8+; avoids the boilerplate of two parallel hierarchies.

The parameterised variant is the most common in practice — many codebases call it “the factory” without subclassing. Strictly, the GoF Factory Method requires subclasses; the parameterised form is what some call a “simple factory” or “static factory.”

Example systems#

The pattern is dense in the JDK and frameworks:

  • java.util.Calendar.getInstance() — returns a GregorianCalendar or a BuddhistCalendar depending on locale.
  • java.text.NumberFormat.getInstance(Locale) — returns a locale-specific number formatter.
  • Collection.iterator() — every collection is the factory for its own iterator.
  • URLConnection openConnection()URL returns a connection appropriate to the protocol (HttpURLConnection, JarURLConnection, etc.).
  • Spring’s BeanFactory — produces beans whose concrete class is determined by configuration.

Trade-offs#

What you gain:

  • Open for extension. New product types are new subclasses; no editing existing code.
  • Encapsulated creation logic. All the new calls for a product family live in one place — easy to audit, easy to change.
  • Polymorphic dispatch instead of conditionals. Replaces sprawling if/else chains over a type discriminator with subclass selection.
  • Testable seams. Override createGateway() in a test subclass to return a stub; no mocking framework required.

What you pay:

  • Class explosion. A parallel hierarchy: every new product needs both a ConcreteProduct and a ConcreteCreator. For small numbers of products this doubles the file count.
  • Two-step dispatch. Clients pick a creator, the creator picks a product — one more layer of indirection than direct construction.
  • Where do you get the creator? Factory Method tells you how to use a creator once you have one; it does not tell you how to pick one. Most codebases end up with a registry or a higher-level factory above the factories.
  • Tempting overuse. If the construction is return new Foo() with no real variation, the factory is pure ceremony.

Factory Method

  • One product type per creator.
  • Subclasses pick the concrete product.
  • The creator hierarchy mirrors the product hierarchy.
  • Adding a product = add one subclass.

Abstract Factory

  • A family of related products per factory.
  • One concrete factory produces matching products together.
  • The factory hierarchy mirrors the product family dimension.
  • Adding a product family = add one factory.
  • Abstract Factory Pattern — Factory Method scaled to families. Abstract Factory is usually implemented using Factory Methods internally.
  • Builder Pattern — Factory Method picks the class; Builder configures the instance. They compose: a factory returns a builder.
  • Singleton Pattern — factories are often singletons. The factory itself is unique; the products it makes are not.
  • Prototype Pattern — an alternative when subclassing is undesirable. Instead of a factory method, register prototype instances and clone them.
  • Open Closed Principle (OCP) — Factory Method is the canonical refactor when a class keeps growing new SomeProduct() calls.
  • Dependency Inversion Principle (DIP) — the creator depends on the product interface; subclasses supply the concrete type. Textbook DIP.
Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.