Introduction
From plain new to a creational pattern
Creational patterns hide how objects are created so clients are not welded to concrete types. They are not a default. The honest starting point is always a plain constructor or new; reach for a pattern only when a real force appears. Two concrete forces are common:
- Force 1 — the concrete type keeps changing. Suppose
Checkoutcreates a payment gateway. With only Stripe in production,new StripeGateway()is correct. The day PayPal is added, every caller that hard-codedStripeGatewaymust be reopened. That is the signal for a factory. The rule: one concrete type → constructor; two or more independently changing types → factory (see Simple Factory vs Factory Method below). - Force 2 — the object has many optional pieces. Building an
HttpRequestwith five positional constructor arguments forces callers to pass placeholders for fields they do not care about and risks swapping two adjacent arguments of the same type. That is the signal for Builder. The rule: one type with many optional or ordered assembly steps → Builder.
// N = 1: plain new is the right choice
PaymentGateway gateway = new StripeGateway();
// N = 2: introduce a factory so callers do not hard-code a concrete type
PaymentGateway gateway = GatewayFactory.create("stripe"); // Simple Factory idiom
// Many optional fields: Builder beats a telescoping constructor
HttpRequest req = HttpRequest.builder()
.url(url)
.timeout(30_000)
.retries(3)
.header("Authorization", token)
.build();
Simple Factory vs GoF Factory Method (do not confuse them)
| Simple Factory | GoF Factory Method | |
|---|---|---|
| Shape | One class (often static) with a switch / map on a type key | Abstract Creator; subclasses override factoryMethod() |
| Add a product | Edit the switch (not Open/Closed) | Add a Creator subclass (Open/Closed) |
| Use when | Few, stable variants; quick wiring | Creation logic varies with a Creator hierarchy / framework hooks |
| Not this | Not a GoF pattern — a useful idiom | Not "any method named factory" |
// Simple Factory — handy, not GoF
Transport t = TransportFactory.create("sea"); // switch inside
// GoF Factory Method — Creator subclasses choose the product
abstract class Logistics {
protected abstract Transport createTransport(); // factory method
void planDelivery() { createTransport().deliver(); }
}
class SeaLogistics extends Logistics {
protected Transport createTransport() { return new Ship(); }
}
Deep dive and when-not (vs DI, Abstract Factory): Factory Method Pattern (FIX / creational deep page in this course).
Hostile-panel drill: defend your creational choice
The interviewer will not let you name a pattern in peace — they will attack the choice. Rehearse the two most common attacks aloud.
Q1. "You wrote
GatewayFactory.create("stripe"). That's a switch on a string. Doesn't that violate Open/Closed — every new provider reopens the factory?"A. Yes, for the switch-based Simple Factory they have a point: adding PayPal edits the
switch, so the factory is not closed to modification. There are two honest escapes. (a) Move to a GoF Factory Method — aCreatorsubclass supplies the product, so a new provider is a new subclass, not an edit. (b) Keep the Simple Factory but replace the switch with a registry/map so adding a provider registers a key instead of editing control flow:// OCP-clean Simple Factory: a registry, not a switch Map<String, Supplier<PaymentGateway>> registry = new HashMap<>(); registry.put("stripe", StripeGateway::new); registry.put("paypal", PayPalGateway::new); // adding a provider = one line, no switch edit PaymentGateway create(String key) { Supplier<PaymentGateway> s = registry.get(key); if (s == null) throw new IllegalArgumentException("unknown gateway: " + key); return s.get(); }The registry closes the factory to modification (new providers register from outside) while staying a one-class idiom — you do not need a Creator hierarchy just to satisfy OCP.
Q2. "When is a factory the wrong tool entirely?"
A. When the caller just needs one dependency supplied and there is no creation logic and no WHICH-concrete decision to make. Then a factory is ceremony: plain constructor injection (DI) is simpler — hand the object its collaborator and let a composition root (or DI container) decide the concrete type once. A factory earns its keep only when the WHICH-concrete choice is non-trivial (varies by input, config, or environment) or must be centralized so callers stop hard-coding it. No variant selection, no assembly logic → DI beats any factory.
Common Creational Patterns
- Singleton — Ensures a single instance and global access. Use sparingly: testability and hidden dependency costs are high.
- Builder — Separates construction of complex objects from their representation; same process, different configs.
- Prototype — Clone a prototypical instance when creation is expensive or configuration-heavy.
- Factory Method (GoF) — Creator subclasses override a factory method to decide which product to instantiate. Do not confuse with a Simple Factory switch.
- Abstract Factory — Creates families of related products without specifying concrete classes.
Why patterns matter
Design patterns are not libraries or syntax rules. They are shared names for recurring solutions so teams can discuss design without redrawing the same diagram. The value is not the pattern itself; it is the ability to say "this is a Factory Method" and have everyone understand the forces, structure, and consequences — including the Simple Factory trap.
How to read a pattern
Every pattern description should answer three questions in order:
- Problem. What design force makes simple code fail? (Example: many optional constructor parameters.)
- Structure. What classes collaborate and what are their responsibilities?
- Consequences. What do you gain and what do you pay? (Example: readable construction, but more classes.)
Pattern-selection flowchart
Start with plain constructor / plain new
|
v
Is there more than one concrete type that changes independently?
| yes
v
Prefer Simple Factory if variants few/stable;
GoF Factory Method if Creator hierarchy / hooks needed;
Abstract Factory for product families
| no
v
Does the object have many optional or ordered parameters?
| yes
v
Use Builder
| no
v
Must exactly one instance exist and be globally reachable?
| yes
v
Use Singleton (and document why it is not a hidden dependency)
| no
v
Keep the plain constructor
When a creational pattern is overkill
Creational patterns pay rent only when creation is non-trivial or varies. Costs include extra classes and files, indirection when reading code, and a composition root or factory to maintain. Skip them when there is exactly one simple concrete type and no realistic second variant — the rule of three applies here too. A LoggerFactory for a single Logger implementation, or a Singleton around a stateless helper, is speculative generality (YAGNI). Prefer constructor injection (DI) when you only need to supply a dependency and there is no Creator template logic. Use the plain constructor until a real second implementation or a genuine optional-parameter explosion arrives.
🤖 Don't fully get this? Learn it with Claude
Stuck on Introduction? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Introduction** (OO & Low-Level Design) and want to truly understand it. Explain Introduction from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Introduction** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Introduction** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Introduction** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.