Singleton Pattern – controlul instanțelor unice în .NET

  • Doru Bulubasa
  • 31 October 2025

Printre cele mai populare modele de proiectare, Singleton Pattern ocupă un loc special. Este simplu de înțeles, dar și ușor de abuzat. Rolul său principal este să asigure că există o singură instanță a unei clase în întreaga aplicație și că oferă un punct global de acces la aceasta.


🧩 Ce este Singleton Pattern

Imaginați-vă o aplicație unde ai nevoie de un serviciu global, cum ar fi:

  • un Logger, care scrie mesaje în consolă sau fișiere;

  • un ConfigManager, care păstrează setările aplicației;

  • o conexiune unică la o bază de date (în anumite scenarii simple).

Dacă fiecare clasă ar crea propriul logger sau propriul manager de configurare, am ajunge la instanțe multiple, inconsistente, greu de controlat.

Singleton rezolvă exact această problemă, asigurând o instanță unică și reutilizabilă în întreaga aplicație.


⚙️ Implementare simplă în C#

Cea mai clasică implementare arată așa:

public sealed class Logger
{
    private static Logger _instance;
    private static readonly object _lock = new();

    private Logger() { }

    public static Logger Instance
    {
        get
        {
            lock (_lock)
            {
                return _instance ??= new Logger();
            }
        }
    }

    public void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now}] {message}");
    }
}

🔹 private Logger() — constructorul este privat, deci nu poți crea obiecte direct.

🔹 static Logger Instance — expune instanța unică.

🔹 lock (_lock) — asigură thread-safety, astfel încât instanța să fie creată o singură dată, chiar și în aplicații multi-threaded.

Utilizare:

Logger.Instance.Log("Aplicația a pornit!");
Logger.Instance.Log("Aceasta este o instanță unică.");

Indiferent de câte ori apelezi Instance, vei primi același obiect.


⚡ Variante moderne – Lazy Initialization

În .NET, putem simplifica și mai mult implementarea, folosind clasa Lazy<T>:

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

    public static Logger Instance => _instance.Value;

    private Logger() { }

    public void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now}] {message}");
    }
}

Avantajul?

Lazy<T> oferă inițializare sigură, thread-safe și creează instanța doar atunci când este nevoie.


💡 Când să folosești Singleton

Cazuri potrivite:

  • Servicii care trebuie să existe o singură dată (logging, caching, configurare).

  • Manageri globali de resurse (ex: API keys, fișiere de configurare).

  • Acces unificat la o componentă comună (ex: sistem de traduceri).

Cazuri de evitat:

  • Când obiectul are stare (stateful), iar acea stare se poate schimba în timp.

  • În testare unit, deoarece Singleton-urile pot fi greu de mock-uit.

  • În aplicații mari, pot crea dependențe ascunse și îngreunează refactorizarea.


🧠 Alternativa: Dependency Injection

În ecosistemul modern .NET, multe dintre cazurile Singleton pot fi rezolvate mai elegant cu Dependency Injection (DI):

Astfel, cadrul (ASP.NET, Blazor etc.) gestionează durata de viață a instanței.

Obiectul este tot unic, dar fără a încălca principiile de inversare a dependențelor.

Singleton devine astfel un concept logic, nu o implementare hard-coded.


🚀 Concluzie

Singleton Pattern este un model simplu, dar puternic, atunci când este folosit corect.

El asigură o instanță unică și acces global, reducând consumul de resurse și menținând consistența aplicației.

Totuși, trebuie folosit cu grijă: un Singleton prost implementat poate duce la cod rigid, greu de testat și de întreținut.

Folosit corect, în combinație cu Dependency Injection, rămâne unul dintre pilonii arhitecturii moderne .NET.

Scrie un comentariu

Adresa de mail nu va fi publicata. Campurile obligatorii sunt marcate cu *