Factory Method
Purpose
Let an inherited algorithm create an object whose concrete type it must not know. The creator
class supplies workflow behaviour and delegates product creation to an overridable method.
Other hooks and creation arguments can coexist with this pattern.
That is a narrow pattern, and most code labelled Factory Method is not it. A static of(...) on
the type itself is a static factory method: a named constructor with the freedom to cache,
return a subtype and be given a meaningful name. It solves a different problem — naming and
control over instantiation — and it involves no subclass and no hook. Both are useful; calling
them the same thing is how a Supplier turns into a class hierarchy.
When it is the answer
Inspect the project's compiler release, toolchain, framework construction path and callers
before changing a public extension point. Examples are partial Java 17 sketches with domain
types/imports omitted; pattern matching over a sealed kind requires Java 21 without preview.
Keep the target baseline; do not upgrade it to adopt an alternative.
An algorithm is inherited, and its only variation point is which
concrete product it creates
→ Factory Method (this is Template Method whose varying step
is construction).
A framework must let unknown subclasses supply the product, and
cannot accept constructor arguments (it instantiates the subclass
itself)
→ Factory Method. This is why frameworks use it and
applications usually should not.
The product type must correlate with the creator's own type — a
DocumentReader subtype pairs with its Document subtype
→ Factory Method, with the covariant return declared.
When it is not
- The creator has no inherited algorithm. Consider a
Supplier, but keep a named domain
provider when checked failures, arguments, lifecycle or a published SPI justify its contract.
- Subclassing exists only to change the created type. Pass the creation function in. One
object with a field beats two types in a hierarchy (
java-composition-over-inheritance).
- The selection is data-driven.
Map<Kind, Supplier<T>> or a sealed Kind with an
exhaustive switch is clearer than a subclass per kind, and the set of kinds is visible in
one place.
- Tests are the reason. Subclassing production code to override
createX() couples the test
to the hierarchy and to protected members; an injected Supplier is a seam that costs
nothing to read (java-test-doubles).
- You mean a named constructor. Write
static Money of(...). Do not build a hierarchy to
get a name.
Modern Java expression
Classical Modern equivalent
─────────────────────────────────── ────────────────────────────────────
abstract class Creator { final class Creator {
abstract Product create(); private final Supplier<Product> create;
void run() { ... create() ... } void run() { ... create.get() ... }
} }
class PdfCreator extends Creator Creator pdf = new Creator(PdfProduct::new);
subclass-per-kind selection Map<Kind, Supplier<Product>>
or sealed Kind + exhaustive switch
open extension by third parties ServiceLoader<ProductProvider>
The method reference PdfProduct::new is a creation function, not the GoF Factory Method
pattern: it preserves deferred creation while replacing inheritance with composition. Keep the
abstract hook when the framework's actual extension contract requires it and offers no suitable
injection seam, or when the product type is covariant and callers rely on that contract.
Decision rules
IF the base class has no behaviour other than the abstract create()
THEN consider a Supplier; preserve meaningful domain and public extension contracts.
IF a constructor calls the overridable factory method
THEN subclass state may still hold default values. Prefer injected creation;
any deferred init must occur after construction and enforce readiness.
IF subclasses exist only to select products and the extension set is application-controlled
THEN composition through suppliers, a keyed map, or a sealed kind is usually simpler.
Keep the hook when open framework extension or creator/product covariance is material.
IF the product must vary per call, from an argument
THEN compare an argument-taking hook with Function<Input, Product>;
arguments do not disqualify Factory Method.
IF several related products must vary together
THEN Abstract Factory, not N independent factory methods
(gof-abstract-factory).
IF the creator caches or reuses what it creates
THEN a lifetime has been introduced. Say what it is; do not let a
factory method quietly become a singleton or a pool.
IF the method is static and lives on the product type
THEN it is a static factory method. Judge it by naming and instance
control (java-object-construction), not by this pattern's criteria.
Cross-cutting checks
- Concurrency. The classic defect is a constructor invoking the overridable factory method:
subclass state can be read before initialization; cross-thread exposure additionally requires
the creator to escape. Avoid overridable constructor calls (
java-composition-over-inheritance).
Lazy caching needs safe publication and an initialization policy: a volatile field alone does
not prevent duplicate creation. Specify failure/retry and disposal of losing instances.
- Distribution. Nothing crosses a boundary here, with one exception: when the product kind
is chosen from externally supplied data (a message type header, a content type), that key must
be validated against a closed set before it selects a class. Reflective instantiation from an
unvalidated name is a deserialisation vulnerability, not a factory.
- Performance. The hook implies neither one allocation nor failed inlining: implementations
may cache products, and HotSpot can inline stable virtual calls. A highly polymorphic hot call
site can inhibit inlining, but only profiles and compilation evidence establish that
(
jit-inlining-and-escape-analysis).
- Testing. An injected
Supplier avoids coupling new tests to protected hooks. A test
subclass can still be a useful characterization seam for an existing public extension point;
do not remove that contract solely to simplify tests.
Review checklist
For a review, return the concrete hook/call sites, creation frequency and ownership, chosen
alternative or reason to retain the hook, and checks performed versus pending. If framework
construction or external subclass usage is unknown, keep removal conditional until inspected.
References
- Decision and alternatives — the three meanings of
"factory method" separated, the hook against
Supplier, keyed maps, ServiceLoader and
dependency injection, the constructor trap in full, and how the pattern relates to Template
Method and Abstract Factory. Read before adding or removing a creation hook.
- Worked example — an import pipeline whose subclasses existed
only to pick a parser, converted to an injected supplier and then to a keyed map, alongside a
framework case where the hook correctly stays. Read when refactoring a creator hierarchy.
1---2name: gof-factory-method3description: Factory Method in modern Java, and the three different things that share its name: the GoF pattern (a creation hook a subclass overrides inside an inherited algorithm), Effective Java's static factory method (a named constructor, not this pattern), and any method someone called createX. Covers when the subclass hook is genuinely right, why an injected Supplier or a keyed map replaces it in most application code, and the constructor-calls-an-overridable-method trap it invites. Use when a protected createX() hook is proposed, when a class is subclassed only to change which type it instantiates, when tests subclass production code to substitute an object, when a static factory is being called Factory Method in review, or when deciding between a subclass hook and a Supplier. Does not cover families of related products (gof-abstract-factory), the surrounding algorithm skeleton (gof-template-method), or static factory naming conventions (java-object-construction).4---56# Factory Method78## Purpose910Let an inherited algorithm create an object whose concrete type it must not know. The creator11class supplies workflow behaviour and delegates product creation to an overridable method.12Other hooks and creation arguments can coexist with this pattern.1314That is a narrow pattern, and most code labelled Factory Method is not it. A `static of(...)` on15the type itself is a **static factory method**: a named constructor with the freedom to cache,16return a subtype and be given a meaningful name. It solves a different problem — naming and17control over instantiation — and it involves no subclass and no hook. Both are useful; calling18them the same thing is how a `Supplier` turns into a class hierarchy.1920## When it is the answer2122Inspect the project's compiler release, toolchain, framework construction path and callers23before changing a public extension point. Examples are partial Java 17 sketches with domain24types/imports omitted; pattern matching over a sealed kind requires Java 21 without preview.25Keep the target baseline; do not upgrade it to adopt an alternative.2627```text28An algorithm is inherited, and its only variation point is which29concrete product it creates30 → Factory Method (this is Template Method whose varying step31 is construction).3233A framework must let unknown subclasses supply the product, and34cannot accept constructor arguments (it instantiates the subclass35itself)36 → Factory Method. This is why frameworks use it and37 applications usually should not.3839The product type must correlate with the creator's own type — a40DocumentReader subtype pairs with its Document subtype41 → Factory Method, with the covariant return declared.42```4344## When it is not4546- **The creator has no inherited algorithm.** Consider a `Supplier`, but keep a named domain47 provider when checked failures, arguments, lifecycle or a published SPI justify its contract.48- **Subclassing exists only to change the created type.** Pass the creation function in. One49 object with a field beats two types in a hierarchy (`java-composition-over-inheritance`).50- **The selection is data-driven.** `Map<Kind, Supplier<T>>` or a sealed `Kind` with an51 exhaustive `switch` is clearer than a subclass per kind, and the set of kinds is visible in52 one place.53- **Tests are the reason.** Subclassing production code to override `createX()` couples the test54 to the hierarchy and to `protected` members; an injected `Supplier` is a seam that costs55 nothing to read (`java-test-doubles`).56- **You mean a named constructor.** Write `static Money of(...)`. Do not build a hierarchy to57 get a name.5859## Modern Java expression6061```text62Classical Modern equivalent63─────────────────────────────────── ────────────────────────────────────64abstract class Creator { final class Creator {65 abstract Product create(); private final Supplier<Product> create;66 void run() { ... create() ... } void run() { ... create.get() ... }67} }6869class PdfCreator extends Creator Creator pdf = new Creator(PdfProduct::new);7071subclass-per-kind selection Map<Kind, Supplier<Product>>72 or sealed Kind + exhaustive switch7374open extension by third parties ServiceLoader<ProductProvider>75```7677The method reference `PdfProduct::new` is a **creation function**, not the GoF Factory Method78pattern: it preserves deferred creation while replacing inheritance with composition. Keep the79abstract hook when the framework's actual extension contract requires it and offers no suitable80injection seam, or when the product type is covariant and callers rely on that contract.8182## Decision rules8384```text85IF the base class has no behaviour other than the abstract create()86THEN consider a Supplier; preserve meaningful domain and public extension contracts.8788IF a constructor calls the overridable factory method89THEN subclass state may still hold default values. Prefer injected creation;90 any deferred init must occur after construction and enforce readiness.9192IF subclasses exist only to select products and the extension set is application-controlled93THEN composition through suppliers, a keyed map, or a sealed kind is usually simpler.94 Keep the hook when open framework extension or creator/product covariance is material.9596IF the product must vary per call, from an argument97THEN compare an argument-taking hook with Function<Input, Product>;98 arguments do not disqualify Factory Method.99100IF several related products must vary together101THEN Abstract Factory, not N independent factory methods102 (gof-abstract-factory).103104IF the creator caches or reuses what it creates105THEN a lifetime has been introduced. Say what it is; do not let a106 factory method quietly become a singleton or a pool.107108IF the method is static and lives on the product type109THEN it is a static factory method. Judge it by naming and instance110 control (java-object-construction), not by this pattern's criteria.111```112113## Cross-cutting checks114115- **Concurrency.** The classic defect is a constructor invoking the overridable factory method:116 subclass state can be read before initialization; cross-thread exposure additionally requires117 the creator to escape. Avoid overridable constructor calls (`java-composition-over-inheritance`).118 Lazy caching needs safe publication and an initialization policy: a volatile field alone does119 not prevent duplicate creation. Specify failure/retry and disposal of losing instances.120- **Distribution.** Nothing crosses a boundary here, with one exception: when the product kind121 is chosen from externally supplied data (a message type header, a content type), that key must122 be validated against a closed set before it selects a class. Reflective instantiation from an123 unvalidated name is a deserialisation vulnerability, not a factory.124- **Performance.** The hook implies neither one allocation nor failed inlining: implementations125 may cache products, and HotSpot can inline stable virtual calls. A highly polymorphic hot call126 site can inhibit inlining, but only profiles and compilation evidence establish that127 (`jit-inlining-and-escape-analysis`).128- **Testing.** An injected `Supplier` avoids coupling new tests to protected hooks. A test129 subclass can still be a useful characterization seam for an existing public extension point;130 do not remove that contract solely to simplify tests.131132## Review checklist133134For a review, return the concrete hook/call sites, creation frequency and ownership, chosen135alternative or reason to retain the hook, and checks performed versus pending. If framework136construction or external subclass usage is unknown, keep removal conditional until inspected.137138- [ ] The creator has real inherited behaviour, not just the hook139- [ ] No constructor calls the overridable factory method140- [ ] The hook is not present solely to give tests a substitution point141- [ ] Subclassing is justified by an inherited algorithm, open extension constraint, or useful142 creator/product type relationship—not merely by a closed application selection table143- [ ] Any externally supplied product key is validated against the supported registry; reflective144 class loading is not driven directly by untrusted input145- [ ] Lazy caching inside the hook, if present, is correctly published146- [ ] Covariant return types are declared where callers depend on the product subtype147- [ ] A `static of/from/valueOf` is described as a static factory, not as this pattern148149## References150151- [Decision and alternatives](references/decision-and-alternatives.md) — the three meanings of152 "factory method" separated, the hook against `Supplier`, keyed maps, `ServiceLoader` and153 dependency injection, the constructor trap in full, and how the pattern relates to Template154 Method and Abstract Factory. Read before adding or removing a creation hook.155- [Worked example](references/worked-example.md) — an import pipeline whose subclasses existed156 only to pick a parser, converted to an injected supplier and then to a keyed map, alongside a157 framework case where the hook correctly stays. Read when refactoring a creator hierarchy.