Singleton
The singleton is a creational design pattern that restricts a class to a single instance and provides a global point of access to it. It is one of the 23 patterns catalogued by the Gang of Four, in the creational category alongside Factory.
A singleton guarantees that one and only one instance of a class exists within a process, and that every caller reaches the same object. The canonical use is a component that coordinates a shared resource or a piece of system-wide state: a configuration manager, a connection pool, a cache, a logger, or a hardware abstraction that owns a single device handle.
How it is built
The pattern is realized with three elements together.
- A private constructor that prevents any other class from instantiating the type directly.
- A static field holding the sole instance.
- A static factory method, conventionally
getInstance(), that returns the instance, creating it on the first call.
The private constructor makes new impossible from outside the class. The
static field stores the one instance once created. The factory method is the
only door through which the rest of the system reaches it.
Initialization strategies
The instance can be created eagerly, at class-loading time, or lazily, on first access. Eager initialization is simple and inherently thread-safe in languages where class loading is itself synchronized, but it pays the construction cost even when the singleton is never used. Lazy loading defers the cost to first use, at the price of extra care.
A naive lazy implementation is not thread-safe: two
threads that call getInstance() simultaneously before the instance exists can
each pass the null check and each create a new instance, defeating the pattern.
The usual remedies are to synchronize the whole factory method, which is
correct but expensive on every call, or to apply double-checked locking, which
synchronizes only the first call and guards the field with a memory barrier so
that the published instance is visible to all threads. In Java, an enum-based
singleton is preferred where it fits, since the language’s enum semantics give
a thread-safe, serialization-safe instance for free.
Trade-offs and criticism
The singleton is the most criticized of the Gang of Four patterns and is often cited as an anti-pattern in modern code. The reasons are not about the idea of having one instance, which is sometimes exactly right, but about the pattern’s mechanism for enforcing it.
- Hidden dependencies. A class that calls
Singleton.getInstance()declares no dependency on its collaborators. The dependency is buried in the method body, invisible to the type system and to readers. This makes the class harder to test in isolation and harder to reason about, the same fault for which the service locator is criticized. - Global state. The instance is reachable from anywhere, so any code can read or mutate it. The result is coupling that the source code does not show: two modules that touch the singleton are connascent in identity, the strongest form in the connascence taxonomy.
- Concurrency pressure. Shared mutable state reachable from every thread is an invitation for concurrency bugs. The double-checked locking dance is one symptom; the broader problem is that the pattern exposes shared state the design did not have to expose.
- Responsibility overload. A singleton manages its own lifecycle and performs its real work, which is two jobs. This is a minor infringement of the single responsibility principle, and singletons tend to grow into the God Object anti-pattern because the one-instance guarantee makes it easy to keep adding responsibilities to the reachable global.
The dependency injection alternative
The modern replacement is dependency injection. Instead of the class enforcing its own singleness, an injector decides that a collaborator’s lifetime is shared and supplies the same instance everywhere it is requested. The class declares its dependency openly, the test substitutes a stand-in, and the lifetime policy lives in configuration rather than in the class.
In the Java ecosystem, Spring Framework beans are
singletons by default, but the singleton-ness is a property the container
manages, not a pattern the bean implements. This is the form the pattern
usually takes in contemporary code: the singleton survives, but as a lifetime
policy applied from outside, not as a hand-rolled getInstance() method.
Relation to single source of truth
A singleton is sometimes confused with single source of truth. The two share the word "single" and almost nothing else. A singleton is a guarantee about the number of object instances in a process; SSOT is a guarantee about where a piece of data is authoritative. A singleton that caches a value does not make that value the source of truth, and a system with a single source of truth needs no singleton to enforce it.
See also
- Design patterns
- Factory
- Anti-pattern
- Dependency injection
- Lazy loading
- Thread safety
- Coupling
- Connascence
- Single responsibility principle
- Single source of truth
- Spring Framework
References
- Gamma, Helm, Johnson & Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. The creational patterns chapter defines the Singleton pattern.