Fabbrica per la creazione di un'istanza singleton

4

Abbiamo un codice legacy che ha un sacco di singleton dappertutto (scritto in C #).

Il singleton è un'implementazione abbastanza "classica" del pattern:

public class SomeSingleton
{
    private static SomeSingleton instance;

    private SomeSingleton()
    {
    }

    public static SomeSingleton Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new SomeSingleton();
            }

            return instance;
        }
    } 
}

Tieni presente che la sicurezza dei thread non è un problema, quindi non vengono utilizzati blocchi.

Per rendere il codice più testabile e senza apportare troppe modifiche, vorrei modificare questo codice per delegare la creazione dell'istanza singleton in un'altra classe (una factory o modello simile).

Questo può aiutare a creare un'istanza di "test" a scopo di test, o la versione reale, come viene usata ora.

È una pratica comune? Non sono riuscito a trovare alcun riferimento a tale modello utilizzato.

    
posta liortal 28.04.2015 - 13:54
fonte

2 risposte

2

Nei commenti dici che stai usando Unity e Mono per lo sviluppo del gioco. Sto indovinando che significa Unity3D non Microsoft Unity. Come tale, raccomanderei di abbandonare il modello singleton che si sta seguendo e invece di utilizzare l'iniezione di dipendenza. Credo che tu possa usare Zenject con il framework unity3d.

La classe singleton verrebbe modificata per essere un'istanza di un'interfaccia come:

public class IImportantInterface
{
  DoSomethingImportant();
}

public class MySingletonImplementation: IImportantInterface
{
  public void DoSomethingImportant()
  {
    Console.WriteLine("This is Important!");
  }
}


public class DoImportantStuff
{
    private readonly IImportantInterface _ImportantInterface;

    public DoImportantStuff(IImportantInterface importantInterface )
    {
    _importantInterface = importantInterface;
    }


    public void DoSomething()
    {
    _importantInterface.DoSomethingImportant();
    }

}

Quindi nella logica di avvio è possibile registrare un'istanza singleton con Zenject:

Container.Bind<IImportantInterface>().ToSingle<MySingletonImplementation>(); 

Un buon post di blog su questo concetto può essere trovato qui: link

    
risposta data 29.04.2015 - 18:16
fonte
0

Ciò richiede l'inversione del controllo. Basta iniziare aggiungendo un'interfaccia a SomeSingleton per dire ISomeSingleton. Quindi tutti i consumatori di ISomeSingleton otterranno solo un parametro costruttore di ISomeSingleton.

Esempio:

public class Consumer1 {
    readonly ISomeSingleton _mySingleton;
    public Consumer1(ISomeSingleton mySingleton) {_mySingleton = mySingleton;}
}

public interface ISomeSingleton{//All your methods you ned.}

public class SomeSingleton : ISomeSingleton
{
    private static SomeSingleton instance;

    public SomeSingleton() // constructor is now public
    {
    }

    public static SomeSingleton Instance // todo remove this when all consumers follow inversino of control pattern.
    {
        get
        {
            if (instance == null)
            {
                instance = new SomeSingleton();
            }

        return instance;
        }
    } 
}

Quando nessun utente chiama direttamente il SomeSingleton, puoi semplicemente rimuoverlo. Questo ti permette di fare il cambio al tuo ritmo.

Ora hai solo bisogno di capire come istanziare SomeSingleton. Puoi farlo manualmente o puoi iniziare a utilizzare un contenitore IOC di cui hai voglia.

Nei test puoi semplicemente creare un'implementazione diversa di ISomeSingleton.

    
risposta data 28.04.2015 - 14:27
fonte

Leggi altre domande sui tag