Singleton

Problemet

Ibland vill du garantera att exakt en instans av en klass finns i hela applikationen — t.ex. en loggningsklass, en konfigurationshanterare.

Lösningen

public class Logger
{
private static Logger? _instance;
private static readonly object _lock = new();
private Logger() { } // Privat konstruktor — ingen utanför kan skapa fler
public static Logger Instance
{
get
{
lock (_lock)
{
_instance ??= new Logger();
return _instance;
}
}
}
public void Log(string message) => Console.WriteLine($"Log: {message}");
}
Logger.Instance.Log("Applikationen startade.");

Den privata konstruktorn stoppar new Logger() utanför klassen. lock skyddar mot att två trådar skapar varsin instans samtidigt vid första anropet — se Threading.

Varför inte bara en static class?

En rimlig fråga — skillnaden:

static classSingleton
Kan implementera interfaceNejJa — viktigt för DI och testning
Kan ärvas/bytas ut i testNejJa, via interfacet
Kontrollerad skapandetidpunktNej — initieras vid första användning automatisktJa, explicit i Instance

Varning — Singleton är kontroversiellt

Singleton är det mest kritiserade GoF-mönstret, och med rätta: det introducerar globalt, delat tillstånd — vilket gör kod svårare att enhetstesta (du kan inte lätt byta ut singletonen mot en testdubblett) och gör dolda beroenden mellan orelaterade delar av koden. I modern ASP.NET Core-kod löses “en instans för hela appen”-behovet oftast bättre med AddSingleton i Dependency Injection — samma livslängdsgaranti, men via ett interface som går att byta ut vid test, istället för hårdkodad global åtkomst.

TL;DR

Singleton garanterar exakt en instans via en privat konstruktor och en statisk åtkomstpunkt. Föredra AddSingleton i en DI-container framför att skriva mönstret för hand när du kan — samma effekt, mindre globalt tillstånd att felsöka.