Versioni
| Conosciuto anche comeNo ha altri nomi. IntentoIl design pattern Singleton permette di assicurare che una classe (Singleton) abbia una unica istanza e che questa sia globalmente accessibile in un punto ben noto. La classe Singleton determina a run-time l'istanza unica da utilizzare quindi questo design pattern è classificato rispetto allo scopo (vedi ClassificazioneDeiDesignPattern#ClassiOggetti) come rivolto agli oggetti. Rispetto al fine questo design pattern è classificato tra i ClassificazioneDeiDesignPattern#Creazionali . Diagramma UML
Un'altro diagramma equivalente qui e qui . MotivazioneAlcuni oggetti rappresentano una entità che per loro natura ha una unica istanza, questa necessità è assolta dal design pattern Singleton che fornisce anche un punto di accesso all'istanza ben noto e globalmente accessibile. Esempi d'uso in .NETUna classe molto usata che implementa il design pattern Singleton è System.DBNull. Altre classi di uso frequente in .NET 2.0 che sono Singleton sono OdbcFactory, OleDbFactory, SqlClientFactory e OracleClientFactory. Note sulla implementazione in .NETDel codice .NET di esempio è disponibile qui . UnicitàCon .NET il design pattern Singleton può garantire l'unicità dell'istanza all'interno di un Application Domain. SerializzazioneQuando un oggetto è serializzabile può essere trasformato in una sequenza di byte ed essere ad esempio salvato su file o passato ad un altro Application Domain (grazie al Remoting avviene un Marshal-by-value). Quando un oggetto Singleton viene deserializzato come è possibile garantire che l'istanza resti unica ossia che la deserializzazione (quando eseguita più volte o quando la gerarchia di oggetti deserializzati referenzia più volte l'oggetto Singleton) restituisca sempre un riferimento alla medesima ed unica istanza? In questo caso è necessario personalizzare la deserializzazione implementando l'interfaccia ISerializable come mostrato in questo esempio . MultithreadingIn generale in un programma .NET sono in esecuzione più soft thread (ad esempio il finalizer thread, i work thread del threadpool, i thread manuali) o in diversti thread effettivi (i thread unmanaged) e ciò può accadere tanto in applicazioni Windows che ASP.NET. La seguente implementazione del design pattern è thread-safe grazie ai meccanismi automatici del CLR e del compilatore:
public static sealed class Singleton
{
public static readonly Singleton Instance = new Singleton();
}
Quando è necessario aggiungere della logica all'istanziazione (perchè ad esempio si vuole specificare un parametro nel costruttore ottenuto da una configurazione esterna,, si vuole tenere conto delle istanze, si vuole usare un pool di istanze invece che una sola) è necessario gestire esplicitamente il problema del multithreading:
public sealed class Singleton {
private Singleton() {}
private static Singleton value;
private static object syncRoot = new Object();
public static Singleton Value {
get {
lock (syncRoot) {
if (Singleton.value == null) {
Singleton.value = new Singleton();
}
}
return Singleton.value;
}
}
Questa implementazione è corretta, il fatto che il lock venga eseguito ogni volta non è efficente se eseguito in macchine multi processore. Nota bene: se il codice implementato non ha dei reali problemi di prestazione dovuti ai lock, il tentativo di applicare delle ottimizzazioni è inutile e rischioso; solo per completezza qui di seguito sono riportate le possibili ottimizzazioni. Verificare la correttezza del codice di sincronizzazione di una implementazione alternativa è un problema complesso, questo è ulteriormente complicato dal fatto che il codice scritto dal programmatore viene sottoposto a diverse modifiche:
il cui effetto può causare dei subdoli malfunzionamenti a seconda del microprocessore usato (se fa uso o meno di alcune ottimizzazioni) e a seconda se si è in presenza o meno di multi processore. Scrivere una versione ottimizzata del pattern che funzioni correttamente su diversi processori e su macchime multi processore è un'impresa ardua! Segue la versione ottimizzata. Il modello di memoria di .NET è definito nella sezione 11.6 della Partition 1 del ECMA standard (il modello viene classificato come weak memory model perché da poche garazine su eventuali riordinamenti di letture e scritture di memoria a beneficio dei costruttori di hardware) e questo fatto da buone speranze che il codice seguente venga eseguito correttamente da ogni implementazione di .NET conforme alle specifiche.
public sealed class Singleton {
private Singleton() {}
private static Singleton value;
private static object syncRoot = new Object();
public static Singleton Value {
get {
if (Singleton.value == null) {
lock (syncRoot) {
if (Singleton.value == null) {
Singleton newVal = new Singleton();
// Insure all writes used to construct
// new value have been flushed.
System.Threading.Thread.MemoryBarrier();
// Publish the new value
Singleton.value = newVal;
} // if null
} // lock
} // if null
return Singleton.value;
}
}
}
Per approfondimenti vedi http://blogs.msdn.com/brada/archive/2004/05/12/130935.aspx . Relazione con altri design patternIl design patter Singleton può essere usato dai pattern PatternAbstractFactory e PatternFacade ma puo essere usato anche per l'implementazione di PatternBuilder e PatternPrototype. Vedi la mappa della RelazioneTraDesignPattern. Approfondimenti
Link
| UGIdotNETWikiUGIdotNETWiki è il WikiWiki italiano dedicato a .NET Se è la prima volta che senti parlare di Wiki, leggi il BenvenutoAiVisitatori e WikiInUnMinuto, oppure il ManualePassoPassoDelWiki. Argomenti Recenti | ||||||||||||||||||||||||||||||||||||||
| © 2008 User Group Italiano UGIdotNET. Tutti i diritti riservati. Note legali | ||||||||||||||||||||||||||||||||||||||||