Questo pattern Γ¨ uno dei pattern creazionali piΓΉ usati che ha lo scopo di garantire che di una determinata classe venga creata una e una sola istanza, e di fornire un punto di accesso globale a tale istanza. E’ un pattern estremamente semplice nella sua struttura in quanto Γ¨ formato da una sola classe, che Γ¨ la classe in questione. La classe singleton ha un unico costruttore privato, in modo da impedire l’istanziazione diretta della classe. La classe fornisce inoltre un metodo β€œgetter” statico che restituisce una istanza della classe (sempre la stessa), creandola preventivamente o alla prima chiamata del metodo, e memorizzandone il riferimento in un attributo privato anch’esso statico. Ogni linguaggio possiede dei trucchi per poter scrivere una classe singleton, il codice indicato qui (preso da http://www.dofactory.com/net/singleton-design-pattern) Γ¨ ottimizzato per .NET, utilizzando le feature che lo contraddistinguono.

private class MainApp
{
/// <summary>
/// Codice Main() della console application.
/// </summary>
private static void Main()
{
//Creo due LoadBalancer e verifico che siano la stessa istanza
LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
if (b1 == b2)
Console.WriteLine("Same instance\n");
}
}
 
/// <summary>
/// LoadBalancer Γ¨ la classe singleton che voglio implementare
/// La classe Γ¨ definita sealed per sottolineare il fatto che non puΓ² avere classi derivate
/// </summary>
private sealed class LoadBalancer
{
// Gli attributi statici di una classe sono inizializzati quando la classe Γ¨ caricata per la prima volta
// Tramite l'attributo readonly impongo che, una volta che viene fatto il load della classe, il valore di _instance non
// possa piΓΉ essere cambiato (ricordo che readonly agisce al caricamento della classe, il const invece durante la compilazione)
//Inoltre questa operazione Γ¨ thread safe di default
private static readonly LoadBalancer _instance = new LoadBalancer();
 
// Attributo della classe: una lista di server
private List<Server> _servers;
 
//Il costruttore Γ¨ privato e non puΓ² essere chiamato dall'esterno
private LoadBalancer()
{
// Il costruttore istanzia una nuova lista di server
_servers = new List<Server>
{
new Server{ Name = "ServerI", IP = "120.14.220.18" },
new Server{ Name = "ServerII", IP = "120.14.220.19" }
};
}
 
// Per avere l'istanza della classe utilizzo questo metodo, che non fa altro che ritornare la variabile _instance
public static LoadBalancer GetLoadBalancer()
{
return _instance;
}
}

Problemi

Il problema del pattern singleton Γ¨ che porta a codice non testabile: come faccio a modificare l’istanza in questione nei test se questa e una e immutabile? L’utilizzo di tale pattern porta spesso a dei code smell simili a quelli di utilizzare classi statiche o variabili globali. La soluzione Γ¨ utilizzare la DI per iniettare a costruttore delle classi normali ed Γ¨ nella DI che dichiaro tale classe come singleton o meno. In questo modo posso testare la classe che riceve l’oggetto singleton semplicemente modificando la DI con una nuova istanza da costruire.