100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Software Design

Singleton Pattern

Ensures a class has only one instance and provides a single global point of access to it.

Creational PatternsBeginner7 min readJul 10, 2026
Analogies

What Is the Singleton Pattern?

Singleton is a creational design pattern that restricts a class to exactly one instance for the lifetime of an application and exposes a single, well-known global point of access to that instance. It is typically implemented by making the constructor private (so external code cannot call new directly) and providing a static accessor method, usually named getInstance(), that creates the instance on first request and returns that same instance on every subsequent call. This guarantees that any part of the codebase referring to the singleton is always referring to the exact same object and its state.

🏏

Cricket analogy: Like how a cricket team has exactly one captain at a time who makes the toss decision — every fielder consults the same single captain instance rather than each having their own version of the decision-maker.

Implementing a Singleton

There are two common initialization strategies: eager initialization creates the single instance immediately when the class is loaded, while lazy initialization defers creation until the first call to getInstance(), saving resources if the singleton is never actually used. In multithreaded environments, naive lazy initialization is unsafe because two threads can both pass a null check before either finishes constructing the object, producing two instances. The standard fix is double-checked locking with a volatile field, or a language-specific guarantee such as Java's enum singleton or Python's module-level instance created once at import time.

🏏

Cricket analogy: Like the DRS (Decision Review System) replay booth that's only switched on the first time a team calls for a review during the match, rather than running continuously from the first ball — that's lazy initialization.

java
public class ConfigManager {
    private static volatile ConfigManager instance;
    private final Map<String, String> settings;

    private ConfigManager() {
        settings = loadFromDisk();
    }

    public static ConfigManager getInstance() {
        if (instance == null) {
            synchronized (ConfigManager.class) {
                if (instance == null) {
                    instance = new ConfigManager();
                }
            }
        }
        return instance;
    }

    public String get(String key) {
        return settings.get(key);
    }
}

Common Pitfalls

The biggest criticism of Singleton is that it introduces hidden global mutable state. Any class that internally calls getInstance() has an implicit, undeclared dependency that isn't visible in its constructor or method signatures, which makes the true dependency graph of a system harder to read from the code alone. This also makes unit testing painful: tests can leak state into one another through the shared instance, and it's difficult to substitute a fake or mock implementation for isolated testing without redesigning the access pattern.

🏏

Cricket analogy: Just as a team that always relies on one senior batsman for every run creates a single point of failure when he's dismissed early, code with hardcoded singleton dependencies collapses when that shared instance misbehaves or needs swapping for a test double.

Global mutable singletons make unit testing hard because tests can leak state into each other through the shared instance. Prefer injecting the singleton as a dependency (constructor or parameter) rather than calling getInstance() deep inside business logic, so tests can substitute a fake.

When to Use Singleton

Singleton is defensible for resources that are genuinely single and shared across an entire application: a logging service, an application-wide configuration manager, or a connection pool. However, even in these legitimate cases, modern practice favors exposing the resource through an explicit, injected reference rather than a hardcoded static accessor buried inside consuming code, because it keeps dependencies visible and testable while still guaranteeing a single shared instance at runtime.

🏏

Cricket analogy: A stadium's single floodlight control system is a legitimate shared resource just like a logging singleton — but modern grounds still let each match director configure it through an explicit interface rather than fielders reaching into the control room directly.

Modern frameworks (Spring's @Singleton scope, Angular's providedIn: 'root', .NET's AddSingleton) let a dependency injection container manage single-instance lifetime for you, giving you the guarantee without a hardcoded static accessor scattered through the codebase.

  • Singleton restricts a class to exactly one instance and provides a single global access point.
  • Implemented via a private constructor plus a static accessor method, often named getInstance().
  • Lazy initialization defers instance creation until first use; eager initialization creates it upfront.
  • Thread-safe lazy singletons typically use double-checked locking or language-level guarantees (e.g., Java enum, Python module import).
  • Overuse creates hidden global state that makes unit testing and reasoning about dependencies harder.
  • Modern practice favors DI-container-managed singleton scope over hardcoded static singletons.
  • Legitimate use cases include logging, configuration managers, and shared connection pools.

Practice what you learned

Was this page helpful?

Topics covered

#SoftwareDesign#DesignPatternsStudyNotes#SoftwareEngineering#SingletonPattern#Singleton#Pattern#Implementing#Common#StudyNotes#SkillVeris