L'uso del pattern Factory solleva un altro problema: chi crea la factory stessa, e come vi si accede?
Innanzitutto si osservi che è necessaria una sola istanza della classe factory. Inoltre la factory (fabbrica di oggetti) suggerisce che i suoi metodi devono poter essere richiamati in vari punti del codice, quindi: come ottenere la visibilità verso tale singola istanza?
Una soluzione consiste nel passare l'istanza di una factory come parametro ovunque sia necessaria la visibilità della stessa, oppure inizializzare gli oggetti che necessitano di visibilità nei confronti di essa con un riferimento permanente (rendere l'istanza di quella factory una variabile di classe delle classi a cui serve).
Una soluzione migliore di queste è offerta da Singleton.
Nome | Singleton |
---|---|
Problema | É consentita (o è richiesta) esattamente una sola istanza di una classe, ovvero un "singleton". Gli altri oggetti hanno bisogno di un punto di accesso globale e singolo a questo oggetto (per esempio una factory) |
Soluzione | Definire un metodo statico della classe che restituisce l'oggetto singleton |
ServicesFactory è la factory creata grazie al pattern Factory, come si vede è presente un metodo getInstance() che ritorna il riferimento del membro ServicesFactory, sia il metodo che l'attributo sono statici. In UML un elemento definito come statico è sottolineato. Il metodo è definito come synchronized poiché è accessibile da diversi punti del sistema per evitare problemi di concorrenza.
Il numerino 1 nella classe ServicesFactory indica che la classe è un singleton, tale notazione può anche essere usata nei DSD.
In qualsiasi punto del codice è possibile quindi fare:SingletonClass.getInstance().metodo()
in tal modo si ottiene la visibilità verso l'istanza della classe singleton e si ci può chiamare un metodo sopra.
Il metodo getInstance() potrebbe venire chiamato spesso.
Una logica di inizializzazione pigra è una sezione critica che richiede il controllo di concorrenza del thread. Supponendo un'inizializzazione di questo tipo, avremmo:
public static synchronized ServicesFactory getInstance(){
// classe della factory
if(instance == null){
// sezione critica se si tratta di una applicazione mutli-thread
instance = new ServicesFactory();
}
return instance;
}
Un altro modo di poter definire il metodo è con una logica che definiamo golosa:
public class ServicesFactory {
// classe della factory
private static ServicesFactory instance = new ServicesFactory();
public static ServicesFactory getInstance() {
return instance;
}
}
in questo caso l'istanza esiste a priori e deve solo essere ritornata.
Nel caso precedente la factory potrebbe non essere mai creata e viene evitato il lavoro per la sua creazione.
Un'altra domanda che potrebbe sorgere sull'implementazione dei Singleton è: perché non far diventare tutti i metodi dei servizi dei metodi statici della classe stessa, anziché utilizzare un oggetto istanza con dei metodi di istanza? Per i seguenti motivi: