What problem do creational design patterns (Singleton, Factory Method, Abstract Factory, Builder, Prototype) solve, and what do they all have in common?
answer
- decouple creation from use
- vary: how many / which class / which family / how assembled / from what
- client holds abstraction, one place names the concrete class
- indirection costs types + traceability
- Factory Method = inheritance; others = delegation
basics
~20 sThey separate creating an object from using it. Instead of calling a concrete constructor directly, code asks something else to produce the object — so the system can change which class is built, and how, without editing every caller.
solid answer
~50 sCreational patterns make a system independent of how its objects are created, composed, and represented. The common mechanism is indirection: replace a hard-coded `new ConcreteThing(...)` scattered across callers with a single creation point — a method, an object, or a copy of an existing instance. That buys three things: (1) callers depend on an abstraction (interface/type) instead of a concrete class, so you can swap implementations; (2) creation knowledge (which class, which arguments, which wiring order, how many instances) is centralized and can vary at runtime or by configuration; (3) construction complexity is hidden behind a simpler API. They differ in *what* they vary: Singleton controls how *many* instances exist; Factory Method defers *which class* to a subclass; Abstract Factory produces *families* of matching products; Builder separates *how* a complex object is assembled step by step from its representation; Prototype creates new objects by *cloning* an existing instance instead of instantiating a class.
code
pseudocode · 8 lines// Coupled: every caller names the concrete class and its wiring
report = new PdfReport(fontLoader, margins, watermark)
// Decoupled: caller asks a creation point for an abstraction
report = reportFactory.create("pdf") // Factory / Abstract Factory
report = ReportBuilder().pdf().withWatermark().build() // Builder
report = templateReport.clone() // Prototype
pool = ConnectionPool.instance() // Singleton accessorgo deeper
State the core idea: separate creating an object from using it, so callers depend on an interface rather than a concrete class, and name the five patterns.
Give one-line intents for each of the five and a concrete example where the indirection paid off (swapping a storage implementation, assembling an object with many optional fields).
Frame it as controlling variation points and binding time, discuss the cost side (extra types, traceability, speculative generality) and when a plain constructor is the right answer.
Talk about creational indirection as an architectural budget: which seams deserve to be pluggable, how DI containers and language features (named/default arguments, records, immutable copy-with) have absorbed much of the classic tooling, and how to keep configuration comprehensible at scale.
## The underlying problem Writing `x = new ConcreteThing(a, b, c)` (or the equivalent in any language) does two things at once: it **names a concrete class** and it **hard-codes how that class is configured**. Both are commitments baked into every call site. That is fine until something must vary: - **Which class?** Test code wants an in-memory store; production wants a database store; a customer wants an S3-backed store. - **How many?** Exactly one connection pool must exist for the whole process. - **How assembled?** The object needs 9 optional settings and two of them are mutually exclusive. - **Which family?** Every widget must come from the *same* theme — a dark button with a light scrollbar is a bug. - **From what?** The cheapest way to get a new object is to copy an expensive, already-configured one. When creation is spread across dozens of call sites, each of these changes means editing dozens of places, and every call site is coupled to a concrete class it does not otherwise care about. ## The shared mechanism: an indirection for creation Every creational pattern inserts something between "I need an object" and "this exact class is instantiated with these exact arguments": | Pattern | Intent (what it lets you vary) | Creation mechanism | |---|---|---| | **Singleton** | *how many* instances exist (exactly one) and global access to it | a controlled accessor that returns the same instance every time | | **Factory Method** | *which concrete class* is created, decided by the subclass | an overridable creation method inside the class that uses the product | | **Abstract Factory** | *which family* of related products is created, decided by which factory object you were handed | a separate factory object with one creation method per product kind | | **Builder** | *how* a complex object is assembled, step by step, independent of its final representation | a builder object that accumulates parts, then produces the result | | **Prototype** | *which object* you start from — new instances are copies of an existing configured instance | `clone`/copy on an existing object, no class named at the call site | Two terms that recur: - **Product** — the object being created. - **Client** — the code that needs the product but should not know its concrete class. ## What you gain 1. **Callers depend on abstractions.** They hold an interface/abstract type; the concrete class name appears in one place. This is the Dependency Inversion Principle applied to construction. 2. **Creation knowledge is centralized.** Which class, which arguments, which order, which lifetime — one place to change, one place to test. 3. **Binding can be deferred.** From compile time to link time, to startup (config file, environment), to runtime (a request header picks the strategy). 4. **Complex construction is hidden.** A caller says `builder.withRetries(3).build()` rather than passing a 9-argument constructor with three nulls. ## What you pay - **More types and more indirection.** A factory hierarchy can double the class count for a system with one implementation. Reading the code no longer tells you what runs; you must trace configuration. - **Harder navigation/debugging.** "Go to definition" lands on an interface. - **Speculative generality.** Indirection added for a variation that never arrives is pure cost. The honest default is a plain constructor; introduce a creational pattern when a *second* variation actually shows up or is contractually required. ## Distinguishing them in one line each - Singleton: *"there must be exactly one."* - Factory Method: *"the subclass decides what to make."* - Abstract Factory: *"make a whole family that matches."* - Builder: *"the same construction process can produce different representations."* - Prototype: *"copy this one rather than build from scratch."* ## Class vs object creational The original Gang of Four book splits them: **Factory Method** is *class* creational — it varies the created class through **inheritance** (you subclass to change the product). The other four are *object* creational — they **delegate** creation to another object (a factory, a builder, a prototype instance), so the variation can be changed at runtime by swapping that object. ## Where they show up even if you never say the name Dependency-injection containers, ORM session factories, HTTP client `.newBuilder()` APIs, logger `getLogger` accessors, connection pools, document "duplicate" commands — all are creational patterns wearing framework clothes.
- If creational patterns are so useful, why not route every object through a factory?Because indirection is not free. Each factory adds types, a level of misdirection when reading code, and configuration that must be tested. Value objects, DTOs, and classes with exactly one implementation and no variation in construction are cheaper as plain constructors. Introduce the pattern when a real second variation, a lifetime constraint, or genuinely complex assembly appears.
- Are static factory methods (e.g. `List.of(...)`, `Optional.of(...)`) a Gang-of-Four creational pattern?Not literally — they are the 'static factory method' idiom, not GoF Factory Method (which relies on subclassing to choose the product). They share the same benefit though: they hide the concrete class, can return a cached instance, and can pick an implementation based on arguments.
- Which creational pattern do dependency-injection containers effectively implement?Mostly Abstract Factory plus lifetime management: the container resolves an abstract type to a configured concrete implementation, wires its dependencies, and enforces scope (singleton/per-request/transient), replacing hand-written factories and hand-rolled Singletons.
Ordering at a restaurant. You say "the special" instead of walking into the kitchen and combining ingredients yourself. The kitchen (creation point) can change the recipe, the supplier, or serve you a plate it prepared earlier — and your order (the call site) never changes.
saying these in an interview costs you the question
- Saying creational patterns exist 'to avoid using new' — the goal is decoupling and controlled variation, not banning constructors
- Treating Factory Method and Abstract Factory as synonyms
- Claiming they always simplify code; they add types and indirection and are a net loss when nothing varies
- Assuming a 'factory' must be a class with `Factory` in the name
- Saying Singleton's point is global access — its defining intent is guaranteeing a single instance; global access is a side effect and often the harmful part