2011-01-19 14 views
15

Sto scrivendo la mia seconda applicazione di vita reale, che utilizza DI. Nel complesso, penso che abbia permesso un design migliore. Ma ci sono alcuni odori di codice, che non so come risolvere.DI: Quanto iniettare?

Preferisco utilizzare l'iniezione del costruttore e ho spesso osservato che ho bisogno di circa 5 o più oggetti da iniettare nel costruttore. Sembra essere troppi, forse è un problema di progettazione, non si ottiene il SRP giusto. Ma penso che anche il mio uso di DI sia da biasimare.

Sto cercando "best practice" o "regola del pollice", in generale mi sembra di iniettare tutto, che non è nel framework .Net, è che esagerare?

Per iniziare, ecco due esempi di oggetti che iniettare, ma non sono sicuro.

Gli oggetti che sono veri singleton come la configurazione dell'applicazione o quelle piccole classi di utilità, vengono iniettati? Sembra che vengano iniettati molto spesso, l'unico motivo per iniettarli sembra consentire di modificare il valore per il test, ma Ayende sembra aver risolto il problema in un altro modo: http://ayende.com/Blog/archive/2008/07/07/Dealing-with-time-in-tests.aspx.

Oggetti comuni come la registrazione, utilizzati in quasi tutti gli oggetti, dovrebbero essere iniettati?

risposta

3

La mia regola personale generale è questo:

  • iniettare se si vuole che sia immutabile
  • iniettare se si vuole essere in grado di sostituirlo a scopo di test

Cose come i servizi possono soddisfare entrambi questi criteri - il consumatore non dovrebbe mai cambiarlo, e tu vuoi essere in grado di sostituirlo con il tempo di test. Con gli oggetti immutabili, si potrebbe ancora possedere una proprietà sull'oggetto consumante, ma quella proprietà avrebbe solo un getter, non un setter. Se si desidera modificare il valore, è necessario creare una nuova istanza dell'oggetto.

In caso di inserimento di logger?

Non c'è motivo di. I logger sono in genere esposti tramite una classe statica e vengono aggiornati dalle voci di configurazione, quindi anche a scopo di test non è necessario iniettarli.

Si devono iniettare veri singleton come la configurazione dell'applicazione?

Ancora una volta, è un oggetto accessibile a livello globale che può essere facilmente modificato a scopo di test, quindi non è necessario iniettarlo. L'unica volta in cui lo inietterei è se il consumatore fosse "disconnesso"; cioè creato tramite riflessione o chiamato come servizio Web o oggetto remoto.

Mentre DI è un modello piacevole, troppa cosa buona può ancora essere malsana. Se percepisci un odore di codice in crescita, esamina ogni elemento che stai iniettando e poniti la domanda: Do i HAI BISOGNO per iniettare questo parametro?

+2

Se si accede alla configurazione dell'applicazione come un globale (o statico), allora la classe dipende tutto di quell'oggetto e sarebbe difficile da usare altrove. Meglio iniettare la parte specifica della configurazione a cui interessa il tuo oggetto. –

12

La regola empirica che uso spesso è quella di iniettare cose che sono nel modo di scrivere correttamente i test unitari. Quando lo fai a volte finisci per astrarre le classi BCL (come DateTime.Ora, File, ecc.) Ea volte le tue cose. Le cose buone da iniettare sono servizi (come ICustomerService, ICustomerUnitOfWorkFactory o ICustomerRepository). Non iniettare cose come entità, DTO e messaggi.

Ci sono altri motivi per iniettare oggetti, tuttavia, in modo da poter sostituire i moduli in un secondo momento (ad esempio implementazioni di switch per la validazione, UI o O/RM), per consentire lo sviluppo parallelo all'interno o tra team, e per ridurre la manutenzione.

I preferiscono usare iniezione del costruttore e hanno spesso osservato che devo circa 5 o più oggetti da iniettare nel costruttore.

Come già notato voi stessi, avere molte dipendenze potrebbe essere causato da non aderire allo SRP. Tuttavia, ciò che si può fare è raggruppare le dipendenze comuni con la logica in un servizio aggregato e iniettarlo nei consumatori. Vedi anche l'articolo di Mark Seemann su Aggregate Services.

oggetti che sono veri single come configurazione dell'applicazione o quelli piccole classi util, fanno si inietta loro?

Personalmente non sono un fan del modo in cui Ayende lo propone. Questo è un Ambient Context, che è un tipo specifico di costrutto service locator. Fare questo nasconde la dipendenza, perché le classi possono chiamare quella classe statica senza doverla iniettare. L'iniezione esplicita rende molto più chiaro che è necessario un tempo di test unitario. Oltre a ciò, rende difficile scrivere test per framework come MSTest che tendono a eseguire test in parallelo. Senza contromisure, rende i test molto inaffidabili. Una soluzione migliore - per l'esempio DateTime.Now- deve avere un'interfaccia IClock, come suggerito here. Come puoi vedere, la risposta ha punteggi molto più alti rispetto all'approccio di Ayende, che è mostrato nella stessa domanda SO.

oggetti comuni, come la registrazione, che vengono utilizzati in quasi ogni oggetto, dovrebbero essere iniettati?

Li inserisco nel mio codice, perché ciò rende chiare le dipendenze. Nota comunque che nel mio codice non ho quasi mai dovuto iniettare un logger. Pensa bene a ogni riga che vuoi registrare e non è davvero un fallimento (o una preoccupazione trasversale che dovrebbe essere posta altrove). Solitamente lancio un'eccezione quando qualcosa non si è aspettato. Mi permette di trovare rapidamente errori. O per dirla in altre parole: non filtrare, ma fallire velocemente. E chiediti: "Do I log too much?"

Spero che questo aiuti.

3

Un buon punto di partenza è iniettare Volatile Dependencies.

Si consiglia inoltre di iniettare Dipendenze stabili per un ulteriore accoppiamento lento, ma se è necessario stabilire una priorità, le dipendenze volatili rappresentano il punto di partenza migliore.

Per quanto riguarda costruttore over-iniezione, in realtà è solo un sintomo di rompere prezzo consigliato: vedi questa domanda correlata: How to avoid Dependency Injection constructor madness?