Easy10 minDesign Patterns
UpdatedAug 2, 2026
Edit

Singleton Design Pattern

Question Variations

  • "What is the Singleton design pattern, and what problem does it solve?"
  • "How do you implement a thread-safe Singleton in your preferred language?"
  • "When can the Singleton pattern be considered an anti-pattern?"
  • "What is the difference between a static class and a Singleton?"

Why This Is Asked

The Singleton is one of the most well-known design patterns. Interviewers use it to check your understanding of object lifecycles, thread safety (Double-Check Locking), and your ability to recognize when a pattern might be an anti-pattern.

Key Concepts

  • Purpose: Ensures a class has only one instance and provides a global point of access to it.
  • Use Cases: Logging, Caching, Database Connection Pools, Configuration settings.
  • Thread Safety: Crucial in multi-threaded environments to avoid creating multiple instances.
  • Dependency Injection: Modern frameworks often manage singletons via the DI container, making manual Singleton implementations less common.

Question Variations

  • “What is the Singleton design pattern, and what problem does it solve?”
  • “How do you implement a thread-safe Singleton in your preferred language?”
  • “When can the Singleton pattern be considered an anti-pattern?”
  • “What is the difference between a static class and a Singleton?”

Answers by Technology

+ Add Variant

Expected Answer (.NET 10 / C# 14)

A Singleton ensures a class has only one instance. In C#, a thread-safe implementation often uses Lazy<T>.

Why use it?: To manage shared resources like a Database Connection Pool, a Log Manager, or a global Configuration object.

Why It Matters

While Singletons provide a global state, they can make unit testing difficult. In modern .NET, we rarely implement the “Classic” Singleton pattern manually. Instead, we register the service with a Singleton Lifetime in the DI container.

Code Example

Classic Thread-Safe Implementation

public sealed class CacheManager
{
    private static readonly Lazy<CacheManager> _instance = 
        new Lazy<CacheManager>(() => new CacheManager());

    public static CacheManager Instance => _instance.Value;

    private CacheManager() { } // Private constructor
}

Modern DI Implementation

// In Program.cs
builder.Services.AddSingleton<ICacheManager, CacheManager>();

Common Mistakes

  • Not being thread-safe: A simple if (instance == null) instance = new ... will fail in multi-threaded environments.
  • Hidden Dependencies: Using MySingleton.Instance deep inside business logic makes it hard to see what a class depends on. Use DI instead.

Follow-up Questions

  • What is Double-Check Locking? (Answer: An older pattern used before Lazy<T> to minimize lock overhead by checking the instance twice).
  • Is a Static Class a Singleton? (Answer: Similar, but a static class cannot implement interfaces or be passed as a parameter easily).

Expected Answer (Java 26)

A Singleton ensures only one instance of a class exists. In Java, there are several ways to implement it:

  1. Enum Singleton: Recommended by Joshua Bloch (Effective Java) because it is naturally thread-safe and resistant to serialization/reflection attacks.
  2. Double-Checked Locking: Using the volatile keyword to ensure visibility across threads.
  3. Static Inner Class: Leveraging the JVM’s class-loading mechanism for thread-safe, lazy initialization.

Why It Matters

In Java enterprise development, most singletons are managed by the Spring IoC Container (using @Service or @Component). Understanding the manual implementation is important for core Java tasks or when working outside of a DI framework.

Code Example

Enum Singleton (Best Practice)

public enum DatabaseConnection {
    INSTANCE;
    
    public void connect() { /* ... */ }
}

Modern Spring DI

@Service // Default scope is Singleton
public class LoggingService {
    public void log(String msg) { /* ... */ }
}

Common Mistakes

  • Not using volatile: In double-checked locking, without volatile, another thread might see a partially initialized instance.
  • Reflection Attack: A manual singleton can be broken via reflection unless the constructor throws an exception if an instance already exists.

Follow-up Questions

  • Is a Singleton in Spring the same as a GoF Singleton? (Answer: No. A GoF Singleton is one per ClassLoader; a Spring Singleton is one per IoC Container).
  • Why use Lazy initialization? (Answer: To save memory and startup time if the object is expensive to create and might not be used).

Expected Answer (PHP 8.5)

A Singleton in PHP ensures a class is instantiated only once per request.

Why use it?: For objects that represent shared resources, like a Database connection (PDO) or a Configuration manager.

Why It Matters

In modern PHP, the “Manual Singleton” (private constructor + static instance) is often considered an anti-pattern. Instead, we use the Laravel/Symfony Service Container to manage singletons. This makes the code easier to test because the container can swap the singleton for a mock during testing.

Code Example

Manual Implementation (Traditional)

class Database
{
    private static ?Database $instance = null;
    private function __construct() {} // Private

    public static function getInstance(): Database
    {
        return self::$instance ??= new self();
    }
}

Modern Container Implementation (Laravel)

// In a Service Provider
$this->app->singleton(Connection::class, function ($app) {
    return new Connection(config('db.dsn'));
});

Common Mistakes

  • Expecting persistence across requests: PHP is “Shared Nothing.” A singleton only lasts for the duration of one HTTP request.
  • Static state in tests: Manual singletons are hard to reset in unit tests, leading to “leaky” tests where one test affects the results of another.

Follow-up Questions

  • What is the ‘Dependency Injection Container’? (Answer: A tool for managing class dependencies and performing dependency injection).
  • Singleton vs Static Class? (Answer: A singleton can be instantiated (once) and can implement interfaces; a static class cannot).

Expected Answer (C++23)

For a process-wide singleton in modern C++, a function-local static is usually the simplest implementation. Since C++11, initialization of a local static is thread-safe: the object is initialized once, and callers wait if another thread is performing that initialization.

Prefer explicit dependency injection when practical because global state hides dependencies and makes tests harder. A singleton should have a clear lifetime and avoid order-dependent initialization across translation units.

#include <string>

class Settings {
public:
    static Settings& instance() {
        static Settings settings;
        return settings;
    }

    std::string environment() const { return "production"; }

    Settings(const Settings&) = delete;
    Settings& operator=(const Settings&) = delete;

private:
    Settings() = default;
};

int main() {
    return Settings::instance().environment() == "production" ? 0 : 1;
}

Why It Matters

This pattern is common for process-wide configuration, registries, and logging, but it can create hidden coupling. Knowing the initialization guarantee avoids unsafe manual double-checked locking.

Common Mistakes

  • Implementing manual lazy initialization without synchronization: Concurrent callers can create or observe partially initialized state.
  • Using a non-virtual public destructor to imply manual ownership: The function-local static owns its lifetime; callers should not delete it.
  • Using a singleton for ordinary dependencies: It makes test replacement and lifecycle control unnecessarily difficult.

Follow-up Questions

  • When is the local static destroyed? (Answer: Normally during program termination, after main returns or std::exit is called.)
  • What is the static initialization order problem? (Answer: Initialization order of non-local statics across translation units is unspecified.)