Design Patterns Mastery

Singleton Pattern: Thread-safety & Captive Dependencies

1 Views Updated 5/4/2026

Singleton Pattern

The Singleton Pattern ensures that a class has only one instance and provides a global point of access to it. While it sounds simple, implementing a truly professional, thread-safe Singleton in .NET requires understanding Lazy Initialization and Double-Check Locking.

1. The Professional C# Implementation

We use the Lazy<T> type. It is natively thread-safe and ensures the object is only created the exact moment someone actually tries to use it.

public sealed class CacheManager 
{
    // The 'Lazy' wrapper handles all lock-checking and thread-safety for us!
    private static readonly Lazy<CacheManager> _instance = 
        new Lazy<CacheManager>(() => new CacheManager());

    public static CacheManager Instance => _instance.Value;

    // Private constructor prevents 'new CacheManager()' from outside
    private CacheManager() { } 

    public void Set(string key, string val) => Console.WriteLine("Cached!");
}

2. Singletons in Dependency Injection

In modern .NET, you don't write "Secret Private Instance" code. You register the class as a Singleton in Program.cs. The DI container handles the "Exactly One" rule for you.

builder.Services.AddSingleton<ICacheService, CacheService>();

3. The Singleton Danger: Captive Dependencies

If your Singleton service (e.g., a Background Worker) tries to inject a Scoped service (e.g., a DbContext), your app will crash or leak memory. Because the Singleton never dies, the Scoped service is "Captured" and never disposed of. This leads to database connections remaining open forever!

4. Interview Mastery

Q: "Is the Singleton pattern an Anti-Pattern?"

Architect Answer: "It depends on *how* it is implemented. The 'Classic' static singleton is often considered an anti-pattern because it introduces global state that is impossible to unit test (you can't mock it). However, using a **DI-managed Singleton** is the industry standard. It gives you all the benefits of a single instance while allowing you to inject interfaces and easily swap implementations during testing."

Design Patterns Mastery
1. Introduction to Design Patterns
Introduction to GoF Patterns: Why patterns matter? SOLID Principles: The foundation of all patterns DRY, KISS, and YAGNI (Architectural Philosophy)
2. Creational Patterns
Singleton Pattern: Thread-safety & Captive Dependencies Factory Method: Abstracting complex object creation Abstract Factory: Creating families of related objects Builder Pattern: Constructing complex fluents Prototype Pattern: Cloning high-cost objects
3. Structural Patterns
Adapter Pattern: Bridging incompatible interfaces Bridge Pattern: Decoupling abstraction from implementation Composite Pattern: Managing tree structures & hierarchies Decorator Pattern: Enhancing behavior without inheritance Facade Pattern: Simplifying complex library subsystems Flyweight Pattern: Drastically reducing memory footprint Proxy Pattern: Interception, Lazy-Loading, and Security
4. Behavioral Patterns
Chain of Responsibility: Middleware & Pipeline Architecture Command Pattern: Implementing Undo/Redo & Queueing Interpreter Pattern: Building domain-specific languages Iterator Pattern: Unified traversal of collections Mediator Pattern: Decoupling components with MediatR Memento Pattern: Capturing and restoring object state Observer Pattern: Pub/Sub & Event-driven architecture State Pattern: Managing complex object lifecycles Strategy Pattern: Swappable algorithms at runtime Template Method: Defining skeleton algorithms Visitor Pattern: Separating operations from data structures
5. Modern Enterprise & Cloud Patterns
Repository & Unit of Work (The EF Core Standard) CQRS Pattern (Command Query Responsibility Segregation) Circuit Breaker & Retry Patterns (Resilience with Polly) Dependency Injection Pattern (The Modern King)