Singleton con iniezione di dipendenza, è una buona pratica in alcuni casi?

2

È una buona idea avere un'implementazione Singleton con iniezione di dipendenza? Ho alcune classi che eseguono alcune attività pesanti sull'istanziazione (relative al caricamento del database). Mi piacerebbe usarli sempre come nuove istanze ma è problematico a causa delle prestazioni. Il codice con cui sto lavorando proviene da un'app legacy, quindi è preferibile non toccarlo troppo.

La mia domanda è: Posso creare singleton come questo esempio?

IMPORTANTE : considerare la dipendenza è una specie di logger, quindi non ho più implementazioni di esso, solo una. Non è un problema se tutte le istanze condividono la stessa istanza di dipendenza.

Sono interessato all'utilizzo di interfacce poiché rendono la mia soluzione meno accoppiata tra i progetti.

public class HeavyTaskDb()
{
   private static HeavyTaskDb instance;
   private IDependency dependency;

   private HeavyTaskDb(IDependency dependency)
   {
      this.dependency=dependency;
   }

   public static HeavyTaskDb Instance(IDependency dependency)
   {  
     if(instance==null)
     {
          instance=new HeavyTaskDb (dependency);}
     }
     return instance;
   }
}
    
posta Badulake 27.09.2017 - 10:49
fonte

1 risposta

8

Questo è problematico, perché se il tuo programma chiama

    HeavyTaskDb.Instance(X)

prima e poi

    HeavyTaskDb.Instance(Y)

più tardi (magari in un'area completamente diversa della base di codice), restituisce un oggetto di tipo HeavyTaskDb inizializzato con X e non come previsto con Y.

Il modo migliore per evitare questo è probabilmente non usare il modello singleton, eseguire l'inizializzazione di una volta contenente htdb=new HeavyTaskDb(X) in una posizione definita e rendere l'oggetto htdb disponibile per tutti gli ambiti in cui è necessario ( magari facendolo passare, magari iniettandolo nelle classi usando, qualunque cosa abbia più senso nel contesto correlato).

Se ritieni davvero che devi avere una variabile globale di tipo HeavyTaskDb nel tuo programma (proprio come il tuo singleton è una variabile globale), allora considera di implementarla in questo modo:

public class HeavyTaskDb()
{
   private static HeavyTaskDb instance;
   private IDependency dependency;

   private HeavyTaskDb(IDependency dependency)
   {
      this.dependency=dependency;
   }
   // call this somewhere at the beginning of the program,
   // before Instance get called
   public static void InitInstance(IDependency dependency)
   {
         instance=new HeavyTaskDb (dependency);
   }

   public static HeavyTaskDb Instance()
   {  
     if(instance==null)
     {
          throw new Exception("instance was forgotten to be initialized")
     }
     return instance;
   }
}

Questa non è ancora una soluzione ideale, ma almeno il chiamante di HeavyTaskDb.Instance non si fa ingannare su quello che ottiene.

    
risposta data 28.09.2017 - 05:57
fonte