Singleton
Da Wikipedia, l'enciclopedia libera.
Nella programmazione ad oggetti, il Singleton è uno dei pattern fondamentali descritti dalla "banda dei quattro" nel celebre libro Design Patterns.
Indice |
[modifica] Scopo
Il Singleton è un design pattern creazionale 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.
[modifica] Implementazione
L'implementazione più semplice di questo pattern prevede che la classe singleton abbia un unico costruttore privato, in modo da impedire l'istanziazione diretta della classe. La classe fornisce inoltre un metodo "getter" statico che ritorna 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. Il secondo approccio si può classificare come basato sul principio della lazy initialization (letteralmente "inizializzazione pigra") in quanto la creazione dell'istanza della classe viene rimandata nel tempo e messa in atto solo quando ciò diventa strettamente necessario (al primo tentativo di uso).
[modifica] Esempio: Java
Il seguente frammento di codice descrive una classe strutturata secondo il pattern singleton nel linguaggio Java:
public class MioSingolo { private static MioSingolo istanza = null; private MioSingolo() {} // Metodo della classe impiegato per accedere al Singleton public static MioSingolo getMioSingolo() { if (istanza == null) istanza = new MioSingolo(); return istanza; } }
[modifica] Esempio: C++
Il seguente frammento di codice descrive una classe strutturata secondo il pattern singleton nel linguaggio C++:
#include <iostream> #define null 0 class singleton { private: static singleton* instance_ptr_; singleton() { }; public: ~singleton() { }; static singleton* get_instance() { if (instance_ptr_ == null) { instance_ptr_ = new singleton; } return instance_ptr_; } bool method() { return true; }; }; // initialize pointer singleton* singleton::instance_ptr_ = null; int main() { std::cout << singleton::get_instance()->method() << std::endl; return 0; }
[modifica] Implementazioni multi-thread
In applicazioni multi-thread l'utilizzo di questo pattern con la lazy initialization richiede un'attenzione particolare: se due thread tentano di eseguire contemporaneamente il costruttore quando la classe non è stata ancora istanziata, devono entrambi controllare se l'istanza esiste e soltanto uno deve creare la nuova istanza.
Il modo più semplice per implementare una versione thread-safe è quello di usare un meccanismo di sincronizzazione come quello fornito dalla parola chiave synchronized di Java. Tuttavia questo approccio è inefficiente: infatti la sincronizzazione è utile solo per la prima inizializzazione, e costituisce un inutile overhead nelle successive chiamate al metodo getter.
[modifica] Esempio: Java
public class MioSingolo{ private static MioSingolo istanza = null; private MioSingolo() {} public static MioSingolo getMioSingolo() { synchronized (MioSingolo.class) { //equivalente a usare l'intero metodo synchronized if (istanza == null) { istanza = new MioSingolo(); } return istanza; } } }
[modifica] Esempio: C#
Ed eccone la traduzione in codice C#. Anche questa implementazione è thread-safe, ed ugualmente inefficiente per l'utilizzo del lock sull'oggetto che funge da semaforo:
public class Singleton { private static Singleton istanza=null; private static object semaforo = new object(); private Singleton() {} public static Singleton Istanza { get { lock(semaforo) { if(istanza==null) istanza=new Singleton(); return istanza; } } } }
[modifica] Inizializzazione preventiva
Se non si vuole incorrere nell'overhead di sincronizzazione, il modo più semplice consiste nel rinunciare alla lazy initialization e creare la prima istanza preventivamente. Le modalità specifiche possono variare da linguaggio a linguaggio. In Java è possibile, per esempio, usare una inizializzazione esplicita dell'attributo statico che contiene il reference all'unica istanza della classe. Tale inizializzazione viene eseguita automaticamente non appena la Java Virtual Machine carica in memoria la classe (un contesto che è intrinsecamente thread safe. Questo algoritmo è stato presentato per la prima volta da William Pugh.
public class Singleton { // private: non viene generato un costruttore pubblico private Singleton() {} /** * La classe Contenitore viene caricata alla prima esecuzione del getInstance() * o al primo accesso a Contenitore.istanza, non prima, e in modo serializzato */ private static class Contenitore { private final static Singleton istanza = new Singleton(); } public static Singleton getInstance() { return Contenitore.istanza; } }
[modifica] Distruggere un singleton (C++)
Il problema della prima implementazione presentata di un singleton in C++ è che non viene chiamato il distruttore al termine del programma. Per risolvere questo inconveniente è sufficiente che l'unica istanza del singleton sia creata da un altro oggetto statico incapsulato nella classe del singleton; in tal caso, il distruttore di questo oggetto viene chiamato al termine del programma e si occupa si distruggere l'istanza del singleton.
[modifica] Critiche
Alcuni autori hanno criticato il pattern Singleton, osservando che, con opportune modifiche strutturali, una istanza singola può entrare più efficacemente a far parte dell' Ambiente globale dell'applicazione[1][2].
[modifica] Collegamenti esterni
- §12.4 of Java Language Specification (JLS) (EN) Sulla serializzazione nell'inizializzazione delle classi
[modifica] Voci correlate
[modifica] Note
- ^ Scott Densmore. Why singletons are evil, May 2004
- ^ J.B. Rainsberger, IBM. Use your singletons wisely, July 2001
| Design patterns nel libro Design Patterns | |
|---|---|
| Creazionali | Abstract factory · Builder · Factory · Prototype · Singleton |
| Strutturali | Adapter · Bridge · Composite · Decorator · Façade · Flyweight · Proxy |
| Comportamentali | Chain of responsibility · Command · Interpreter · Iterator · Mediator · Memento · Observer · State · Strategy · Template method · Visitor |

