Come dovrei refactoring un singleton (che deve essere usato da un contenitore) quando la classe refactored richiede l'inizializzazione e prende una dipendenza?

0

Sto refactoring di una vecchia app per usare dependency injection.n Sono abbastanza nuovo per DI.

Ho una classe che era un singleton. Sto refactoring in una classe non-singleton e utilizzo del contenitore per gestire la sua durata (come una singola istanza). Ha un po 'di inizializzazione che era solito fare nel costruttore ma sembra che questo sia generalmente disapprovato nel mondo DI: SRP dice che i metodi dovrebbero solo fare una cosa e quindi i costruttori sono solo per le dipendenze, ho letto da qualche parte.

Se la classe non avesse dipendenze, potrei semplicemente creare l'istanza, chiamare .Initialize () e registrare l'istanza con il contenitore come un singleton. Ma la classe ha una dipendenza che preferirei risolvere usando il contenitore.

Sto andando su questo nel modo sbagliato? Mi manca qualche motivo?

    
posta user2871239 24.06.2015 - 12:36
fonte

3 risposte

1

"SRP dice che i metodi dovrebbero fare solo una cosa". Vero. I costruttori dovrebbero fare solo una cosa, e cioè mettere l'oggetto in uno stato utilizzabile. Se la semplice memorizzazione delle dipendenze non mette l'oggetto in uno stato utilizzabile, allora il costruttore non sta facendo il suo lavoro.

Hai letto da nessuna parte che "i costruttori con l'iniezione delle dipendenze dovrebbero solo impostare le dipendenze e non dovrebbero fare nient'altro"? Io non la penso così

    
risposta data 24.06.2015 - 14:56
fonte
0

Non sai quale lingua stai usando, quindi sto usando pseudo-C # come esempio.

Puoi creare un'interfaccia IInitializes , che chiamerai dopo la creazione delle istanze.

public interface IInitializes
{
   void Initialize();
}

public class PreviousSingleton : IPreviousSingleton, IInitializes
{
    IDependency dep;

    public PreviousSingleton(IDependency dep)
    {
        this.dep = dep;
    }

    public void Initialize() {
        // do whatever with dep
    }
}

Poi quando ti registri e lo crei usando IoC:

IoC ioc;
ioc.RegisterAsSingleton<PreviousSingleton>(); // make sure IoC recognizes it as both having IPreviousSingleton and IInitializes interfaces

// do rest of the registrations

// and after registrations are done, run initialization
var instancesToInitialize = ioc.GetAllInstances<IInitializes>();
foreach(var inst in instancesToInitialize)
{
    inst.Initalize();
}

var noLongerSingleton = ioc.GetInstance<IPreviousSingleton>(); // should be initialized now

Funziona, perché solo una istanza verrà mantenuta all'interno di IoC, il che significa che la stessa istanza verrà inizializzata come una che verrà passata ad altri oggetti. Funziona anche se hai più classi diverse che implementano IInitializes .

    
risposta data 24.06.2015 - 13:33
fonte
0

"Ha un po 'di inizializzazione che era solito fare nel costruttore ma sembra che questo sia generalmente disapprovato nel mondo DI" - questo non è esattamente vero. DI sta semplicemente fornendo dipendenze esternamente non creandole all'interno di un oggetto.

Quindi la prima cosa che devi fare è identificare, all'interno del tuo singleton, quali sono le sue dipendenze e quali sono gli altri oggetti che usa solo per eseguire la sua logica, ma non devono essere creati esternamente.

Ad esempio, supponiamo di avere OldSingletonClass che utilizza istanze di classi C1 e C2, che hanno le loro dipendenze. Questi dovrebbero ovviamente essere iniettati. Ma diciamo che questa classe dovrebbe fare alcune chiamate HTTP e l'hai implementata con un HttpClient e questo HttpClient non prende alcuna dipendenza. Direi che in questo caso puoi tranquillamente crearlo in costruttore (se ovviamente ha senso mantenere una singola istanza).

Per quanto riguarda la creazione di materiale nel metodo constructor vs Initialize () - la mia esperienza è che a volte è scoraggiato a fare troppe cose in Ctor a causa di diversi problemi di ereditarietà degli oggetti, ma a parte questo è solo una questione di stile Ultima cosa, ricorda che DI non richiede l'uso del DI-container. È spesso molto utile se si lavora con tonnellate di oggetti e alcuni framework che "magicamente" creano nuove istanze (controller ASP.NET MVC per esempio), ma nel caso in cui si abbiano, diciamo, 20 oggetti, tutti creati all'applicazione avvio, trovo che sia spesso molto più pulito collegarli insieme in codice.

    
risposta data 24.06.2015 - 13:40
fonte