The three GoF families and the patterns worth knowing cold, then Singleton in depth — purpose, thread-safe implementations, lazy initialisation, defending against serialization and reflection, and when to avoid it.
Published September 25, 2026
Pattern questions at this level are judged on when you'd use a pattern, and what it costs, not on reciting UML. For every pattern in this chapter, have one real example from your own systems ready, and one situation where you'd deliberately not use it.
Short answer: Creational patterns control how objects are created, decoupling clients from concrete classes:
Learn it in depth → Singleton Pattern
Short answer: Structural patterns deal with how classes and objects are composed:
Learn it in depth → Adapter & Facade
Short answer: Behavioural patterns deal with communication and the division of responsibility between objects:
Key points to cover:
Learn it in depth → Strategy Pattern
Short answer: Singleton guarantees that a class has exactly one instance (per class loader), and provides a well-known access point. It's useful for truly process-wide, shared resources where several instances would be wrong or wasteful: a metrics registry, a configuration snapshot, a thread-safe cache, a hardware or device handle.
Key points to cover:
Short answer: The three recommended forms:
// 1) Enum: simplest; thread-safe, serialization-safe and reflection-safe
public enum MetricsRegistry { INSTANCE; public void inc(String name) { /* … */ } }
// 2) Initialization-on-demand holder: lazy, lock-free, relies on the JVM's class-init guarantees
public final class Config {
private Config() { }
private static final class Holder { static final Config INSTANCE = new Config(); }
public static Config getInstance() { return Holder.INSTANCE; }
}
// 3) Double-checked locking: lazy; volatile is REQUIRED
public final class Registry {
private static volatile Registry instance;
public static Registry getInstance() {
Registry r = instance;
if (r == null) {
synchronized (Registry.class) {
r = instance;
if (r == null) instance = r = new Registry();
}
}
return r;
}
}
Common trap: double-checked locking without volatile. Reordering can let another thread see a non-null reference to an object that isn't fully constructed yet.
Short answer: Creating the instance on first use, rather than when the class loads. It's worth it when construction is expensive (loading large data, opening resources), and the singleton might not be needed at all. The holder idiom gives laziness for free, because the nested class initialises only when getInstance() first touches it.
Key points to cover:
Short answer:
readResolve() returning the existing instance, and make the instance fields transient. Deserialization then discards the new copy.private constructor alone does not stop reflection, because setAccessible(true) bypasses it. Add a guard that throws if an instance already exists, or better, use an enum. The JVM forbids reflective creation of enum instances.Cloneable, or override clone() to throw.private Singleton() {
if (Holder.INSTANCE != null) throw new IllegalStateException("already initialised");
}
private Object readResolve() { return Holder.INSTANCE; }
Common trap: "make the constructor private to prevent reflection". That's precisely what reflection bypasses.
Short answer: Most of the time, in application code:
X.getInstance() instead of declaring what they need.Better: dependency injection with singleton scope (Spring beans), which gives one instance with explicit, mockable dependencies. For cluster-wide uniqueness (for example, one scheduler instance), use a distributed lock or leader election.
Q: Is a Spring singleton bean the same as the GoF Singleton? A: No. Spring guarantees one instance per application context, created and injected by the container. The class itself doesn't enforce uniqueness, and a test can create more instances.
Q: Can a singleton have multiple instances in one JVM? A: Yes, if the class is loaded by several class loaders (app servers, plugins), because each loader gets its own class and static state.
Q: Is the enum singleton lazy? A: The enum constant is created when the enum class is initialised, which happens on first use of the enum. So it's effectively lazy, unless other code touches the enum earlier.
Q: Which JDK classes follow the Singleton pattern?
A: Runtime.getRuntime(), Desktop.getDesktop(), and System's static facilities (not a singleton instance, but global state). Many JDK "singletons" today are enum constants or cached immutable instances (Collections.emptyList()).