Factory Method Pattern
Defer instantiation to a method subclasses override. The seam between knowing what to make and knowing how to make it.
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 protected — factoryMethod() 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
newcalls 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
ShapeCreatorsubclasses (CircleCreator,SquareCreator) each return their ownShape. - Payment processors — a
PaymentGatewaybase with subclassesStripeGatewayandPaypalGateway, each instantiating their own client connection. - Database connectors — a
ConnectionFactorywhoseMySqlFactory/PostgresFactorysubclasses construct the rightConnection. - Document parsers —
Documentsubclasses that each create their own kind ofParser.
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
AdyenProcessorrequires zero changes toPaymentProcessor. That is the Open-Closed Principle in action. - The factory method is
protected. Clients callprocess(), notcreateGateway(). The factory method is an extension point, not a public API. - Return type is the interface.
createGateway()returnsPaymentGateway, notStripeGateway. 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#
| Variant | Mechanism | When 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 method | One 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 method | public 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 factory | Supplier<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 aGregorianCalendaror aBuddhistCalendardepending 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()—URLreturns 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
newcalls for a product family live in one place — easy to audit, easy to change. - Polymorphic dispatch instead of conditionals. Replaces sprawling
if/elsechains 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
ConcreteProductand aConcreteCreator. 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.
Related patterns#
- 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.