UGIdotNET Home UGIdotNET Home
UGIdotNET Blogs UGIdotNET Blogs
UGIdotNET Forum UGIdotNET Forum
MSDN Architetti MSDN Architetti
Visualizza Modifiche Visualizza Modifiche
Modifica Modifica
Stampa Stampa
Modifiche Recenti Modifiche Recenti
Sottoscrizioni Sottoscrizioni
Ufficio Oggetti Smarriti Ufficio Oggetti Smarriti
Cerca Riferimenti Cerca Riferimenti
Rinomina Rinomina
Cerca

Versioni

06/06/2008 1.00.50
88.149.244.206
15/05/2008 22.05.02
-213.156.52.112
31/05/2007 8.21.44
-88.149.170.185
14/06/2006 13.46.00
SimoneBusoli-80.104.175.28
30/12/2005 0.41.51
LucaMinudel-151.47.142.68
Elenco completo versioni Elenco completo versioni
Pattern Singleton
.
Summary un design pattern che rende unica e globale l'istanza di una classe.

Conosciuto anche come

No ha altri nomi.

Intento

Il 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 .

Motivazione

Alcuni 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 .NET

Una 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 .NET

Del 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.

Serializzazione

Quando 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 .

Multithreading

In 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:

  • ottimizzazioni da parte del compilatore C# e IL
  • ottimizzazioni dipendenti dal modello di memoria del CLR
  • ottimizzazioni dipendenti dal modello di memoria del microprocessore

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 pattern

Il 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

  • Quando design pattern Singleton viene usato per rendere dei dati globali come fossero delle variabili globali di VB6 e non per rappresentare una entità che per sua natura ha una unica istanza, accade che il disegno peggiora invece di migliore perché aumenta l'accoppiamento e diminuisce la comprensibilità del codice.
  • In alcuni linguaggi come il C# alcune funzionalità (ad esempio il modificatore virtual) disponibili per i metodi di istanza non sono disponibili per i metodi static quindi il Singleton in questi casi viene usato per sostiuire una classe static con una classe istanziabile.

Link

VediAnche CatalogoDeiDesignPattern, DesignPattern#PatternComuni

UGIdotNETWiki

UGIdotNETWiki è 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

  • PatternSingleton
© 2008 User Group Italiano UGIdotNET. Tutti i diritti riservati. Note legali