Pattern Singleton con parametri

Attraverso il pattern Singleton, siamo in grado di rendere disponibile un’unica istanza di una classe in un qualunque punto di un’applicazione essa venga referenziata, in quanto l’allocazione dell’oggetto avviene una sola volta in corrispondenza del primo accesso.

L’implementazione più semplice del pattern, senza considerare le problematiche di thread-safety (per le quali vi rimando a questo link), prevede all’interno della classe stessa :

  • un campo privato statico “instance” che rappresenterà l’unica istanza della classe a cui appartiene;
  • un costruttore privato, quindi non invocabile dall’esterno, che istanzia la classe assegnando il riferimento al campo suddetto;
  • un metodo o una proprietà che ritorna il riferimento al campo privato in maniera intelligente, creando l’istanza della classe se non esiste oppure ritornando il suo riferimento se la stessa è stata già allocata;

Poiché poche righe di codice riescono ad esprimersi più di mille parole, riporto di seguito la versione base di implementazione del pattern :

<br />public class MyClass<br />{<br />    private MyClass instance = null;<br />    ...<br />    ...<br />    private MyClass()<br />    {<br />        // costruzione oggetto<br />    }<br />    ...<br />    ...<br />    public MyClass Instance<br />    {<br />        get<br />        {<br />            if (instance == null)<br />                instance = new MyClass();<br />            return instance;<br />        }<br />    }<br />}<br />

Nel caso in cui abbiamo necessità di passare dei parametri in fase di allocazione dell’oggetto, come possiamo comportarci ?

Una possibilità potrebbe essere quella di implementare un metodo GetInstance() in luogo della property Instance e predisporlo con dei parametri in ingresso.

Ad esempio, nel caso di due parametri :

private MyClass(int param1, int param2)
{
    // costruzione oggetto
}

public MyClass GetInstance(int param1, int param2)
{
    if (instance == null)
        instance = new MyClass(param1, param2);
    return instance;
}

Con questa soluzione, si può dar luogo ad un’ambiguità. Basta considerare il seguente esempio :

MyClass a = MyClass.GetInstance(1,2);
MyClass b = MyClass.GetInstance(3,4);

Chi lavora con l’oggetto a, si aspetta di aver inizializzato correttamente l’oggetto con i valori 1 e 2. Chi lavora con l’oggetto b, invece, si aspetta di avere un oggetto il cui stato interno ha valori 3 e 4. Ovviamente, la prima inizializzazione prevarrà sulla successiva e quindi sia il riferimento a che b punteranno al medesimo oggetto avente stato con valori 1 e 2 (positivo per a ma non per b).

Una soluzione a questo problema può essere quello di implementare il pattern nel modo seguente :

public class MyClass
{
    private MyClass instance = null;
    ...
    ...
    private MyClass(int param1, int param2)
    {
        // costruzione oggetto
    }

    public MyClass GetInstance()
    {
        if (instance == null)
            throw new InvalidOperationException("MyClass instance not created !");
        return instance;
    }

    public static MyClass Create(int param1, int param2)
    {
        if (instance != null)
            throw new InvalidOperationException("MyClass instance already created !");

        instance = new MyClass(param1, param2);
        return instance;
    }
}

In pratica, viene fornito all’esterno un metodo statico di Create() per la prima allocazione dell’oggetto ed il metodo GetInstance() per ricavarne l’istanza corrente. Una doppia chiamate al metodo Create() solleverebbe l’eccezione “oggetto già creato” così come una chiamata alla GetInstance() senza aver prima creato l’oggetto, solleverebbe l’eccezione “oggetto non creato”.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s