2.2.10 · D5Design Principles
Question bank — Design Patterns — Creational - Singleton, Factory Method, Abstract Factory, Builder, Prototype
Before we start, three words we reuse constantly:
- Concrete class ::: the actual class you can
new— e.g.WinButton, not the interfaceButton. - Client ::: any code that uses an object but should not know how it was built.
- Invariant ::: a rule the object must always satisfy (e.g. "a pizza always has a size").
Anchor: the wall every creational pattern builds
Before the traps, one picture to hold in your head. Every creational pattern puts a wall between the client (who wants an object) and the concrete class (the real thing being new-ed). The client only ever talks to an interface; the messy new lives on the far side of the wall.

The Singleton thread-safety ladder (define "holder idiom" now)
Several traps below hinge on how a lazy Singleton behaves with multiple threads. Here is the full ladder, from broken to safe, so the terms are earned before you meet them.

// 1) NAIVE (broken under threads)
static Logger getInstance() {
if (instance == null) instance = new Logger(); // race here
return instance;
}
// 2) DOUBLE-CHECKED LOCKING (works, but subtle)
private static volatile Logger instance; // volatile is REQUIRED
static Logger getInstance() {
if (instance == null) { // 1st check: fast path, no lock
synchronized (Logger.class) {
if (instance == null) // 2nd check: inside lock
instance = new Logger();
}
}
return instance;
}
// 3) HOLDER IDIOM (cleanest)
private static class Holder { static final Logger I = new Logger(); }
static Logger getInstance() { return Holder.I; } // JVM guarantees one, lazilyTrue or false — justify
True or false: The naive lazy Singleton (if (instance == null) instance = new ...) is thread-safe.
False — two threads can both see
null at the same moment and each run new, producing two instances; use double-checked locking or the holder idiom shown above.True or false: Double-checked locking works without marking the instance field volatile.
False — without
volatile, another thread can see a non-null but half-constructed object due to instruction reordering; volatile forbids that reordering and makes DCL correct.True or false: A Singleton is always good design because it removes duplication.
False — it is global mutable state in disguise; it hides dependencies and breaks unit tests, so prefer Dependency Injection unless the resource is truly unique.
True or false: Factory Method and Abstract Factory are the same pattern.
False — they share the goal of hiding
new, but the mechanism differs: Factory Method varies one product by subclassing, Abstract Factory varies a family by composition (passing a factory object).True or false: A Builder is just a class full of setters.
False — setters mutate an existing object; a Builder assembles a new object and can enforce invariants in
build() before any client ever sees it.True or false: Prototype's clone() always gives you an independent copy.
False — a shallow clone copies references, so clone and original share nested mutable objects; you need a deep copy for those fields.
True or false: If you make the constructor private, the class automatically becomes a Singleton.
False — a private constructor only blocks outside
new; you still need a static field to hold one instance and a static access method to hand it out.True or false: Abstract Factory guarantees its products match.
True — that is its whole job; a single
WinFactory builds WinButton and WinCheckbox, so a client can never accidentally mix a Windows button with a Mac checkbox.True or false: Builder is pointless for a class with two required fields and no optional ones.
True — Builder pays off when constructors telescope (many optional params); for a small fixed constructor it is just ceremony.
Spot the error
getInstance() calls new Logger() every time and returns it — what breaks the Singleton?
There is no cached static field, so every call builds a fresh object; "at most one instance" is violated — you must store and reuse the first one.
A DCL Singleton uses private static Logger instance; (no volatile) — what's the latent bug?
A thread may publish a reference before the constructor finishes, so another thread sees a half-built object; add
volatile to forbid that reordering.A WindowsDialog.render() method itself writes new WindowsButton() — why is Factory Method not really being used?
The whole point is to move
new out of shared logic into an overridable createButton(); hard-coding the concrete class in render() re-couples the workflow to one product.An Abstract Factory client does if (os == WIN) new WinButton() else new MacButton() inside its own code — what did it lose?
It lost the wall — the client now knows every concrete class and must be edited for each new OS; the factory object exists precisely to hide that branch.
A Builder's build() just does return this.pizza; with no checks and pizza is mutable — what invariant risk appears?
Clients receive a live, mutable, possibly half-configured object;
build() should validate invariants and return an immutable finished product.Circle.clone() does Circle c = new Circle(); c.points = this.points; return c; where points is a List — what's the bug?
Both objects now share the same list reference (shallow copy); adding a point to the clone mutates the original too — copy the list contents for a deep clone.
Someone marks a Singleton field public static Logger instance; (no method) — why is this fragile?
A public mutable static field lets any code reassign or null it, destroying the single-instance guarantee; expose it only through a controlled
getInstance().Why questions
Why is render() placed in the base Dialog class and not each subclass?
Because the workflow (create → onClick → draw) is identical everywhere; only the product choice varies, so we share the workflow and override just the creation hook.
Why does Builder call build() at the very end instead of returning the object after each step?
So the object stays half-built and private during assembly and only becomes a validated, immutable result once all steps finish — no partial object ever leaks.
Why prefer Prototype over calling the constructor when spawning 1000 identical enemies?
If construction is expensive (DB load, config parsing), doing it once and cloning the template avoids paying that cost 1000 times.
Why does Abstract Factory swap families by passing an object rather than by subclassing like Factory Method?
Passing a factory object lets you switch the whole product family at runtime with a single reference change, no new subclass required.
Why does double-checked locking check null twice instead of just locking once?
The outer check skips the expensive lock on the common path (instance already built); the inner check, held under the lock, ensures only the very first thread actually constructs it.
Why is the holder idiom both lazy and thread-safe with no locks?
The JVM guarantees a static nested class is loaded exactly once, on first reference, and class loading is inherently synchronized — so the instance is built lazily and safely for free.
Why is Singleton criticised for hurting unit tests specifically?
Because tests rely on isolating and swapping dependencies; a global Singleton is grabbed directly inside code, so you can't substitute a fake, and its state leaks between tests.
Edge cases
What should getInstance() do the very first time it is ever called (the cold-start case)?
On the first call the instance is still
null/unloaded, so this is exactly when it builds the one object; every later call must reuse that same one.If a "Singleton" class is loaded by two different class loaders, how many instances can exist?
Two — the "one instance" guarantee is per class loader, so separate loaders each get their own, a classic hidden multiplicity bug.
For Builder, what happens if a required field is never set before build()?
build() should detect the missing invariant and fail loudly (throw), rather than returning an object that silently violates its own rules.For Prototype, what is the safest clone when an object has no nested mutable fields (only primitives/immutables)?
A shallow copy is already safe — with nothing mutable shared, clone and original can never corrupt each other, so deep copying would be wasted work.
For Abstract Factory, what is the degenerate case where it collapses into plain Factory Method?
When the "family" has exactly one product; a factory with a single create-method carries no consistency benefit over a lone Factory Method.
If two threads both call a correctly-written holder-idiom getInstance() at the same instant, how many objects are created?
Exactly one — class initialization is serialized by the JVM, so the second thread waits and receives the same instance the first thread's load produced.
Recall One-line self-test
The five "questions they answer": want exactly one? Singleton. Choose a subclass's product? Factory Method. Need a matching kit? Abstract Factory. Too many optional args? Builder. Copy an existing object? Prototype.