2009-10-16 21 views
39

Ho avuto una certa sensazione in questi ultimi due giorni che l'iniezione di dipendenza dovrebbe essere davvero chiamata "Non riesco a decidermi" -pattern. So che questo potrebbe sembrare sciocco, ma in realtà riguarda il motivo dietro il quale dovrei usare Dependency Injection (DI). Spesso si dice che dovrei usare DI, per raggiungere un livello più alto di accoppiamento libero, e ottengo quella parte. Ma davvero ... quanto spesso cambio il mio database, una volta che la mia scelta è caduta su MS SQL o MySQL .. Molto raramente vero?Quando usare Dipendenza iniezione

Qualcuno ha alcune ragioni molto convincenti perché DI è la strada da percorrere?

+3

Mi piacciono tutte le tue ragioni finora ... Capisco che per lo più sono programmatori esperti che "ottengono" DI. Come ho capito, DI riguarda la qualità. Noi, come programmatori, vogliamo produrre il massimo livello di software che possiamo - e testarlo aiuta. Ho scritto molto del codice nel corso degli anni, e sono felice di dire che 10 anni fa, oltre il 50% di esso è ancora in esecuzione .. e che senza DI. Forse questo ti aiuta a capire perché sono un po 'riservato a DI? – CodeMonkey

+0

Ovviamente DI è relativamente relativamente nuovo. Quindi, naturalmente, è possibile scrivere software di alta qualità senza di esso - ma con il progresso di cose come framework di test e TDD, DI può rendere molto più facile scrivere test e scrivere codice che è gestibile per il futuro (accoppiamento). – digiarnie

risposta

44

Due parole, test di unità.

Uno dei motivi più convincenti per DI è quello di consentire un più facile test delle unità senza dover colpire un database e preoccuparsi di impostare i dati di 'test'.

+2

Quindi stai dicendo di disaccoppiare il database e "fingere", usando alcuni oggetti falsi invece di cambiare il mio DB durante i miei test unitari ... hmm ... suona come un argomento ragionevole in realtà !! – CodeMonkey

+0

Ma dal momento che si tratta di un database di test, è davvero importante che il mio database sia aggiornato ?? – CodeMonkey

+5

I test saranno eseguiti molto più velocemente senza dover colpire un vero database. Inoltre, quando si esegue il test per casi specifici, è molto più semplice impostare i casi specifici in un oggetto fittizio anziché preoccuparsi se il database di test è in uno stato corretto oppure no. –

1

A parte l'accoppiamento libero, il collaudo di qualsiasi tipo è ottenuto con maggiore facilità grazie a DI. Puoi sostituire una dipendenza esistente di una classe sotto test con un finto, un manichino o anche un'altra versione. Se una classe viene creata con le sue dipendenze direttamente istanziate, spesso può essere difficile o addirittura impossibile "stopparle" se necessario.

+0

Potrebbe approfondire i termini "stub" e "finto" ... presumo "finto" è quello che ho fatto riferimento a come "falso" -Oggetti – CodeMonkey

+2

Con stub Stavo riferisco a sostituire qualsiasi dipendenza con qualcosa di "altro" per test. Per finto intendo usare una libreria come jmock o mockito (se usi java ovviamente) per creare un proxy in cui dichiari aspettative su quell'oggetto "finto". È anche possibile creare una versione fittizia di una classe implementando l'interfaccia della dipendenza. – digiarnie

+0

Quando prendi in mano l'oggetto, lo registrate nel registro di registrazione o semplicemente passate l'oggetto fittizio? tramite il costruttore, per esempio. – liang

5

Mentre sono semi-d'accordo con voi con l'esempio DB, una delle grandi cose che ho trovato utile usare DI è di aiutarmi a testare il livello che costruisco in cima al database.

Ecco un esempio ...

Tu hai il tuo database.

Tu hai il tuo codice che accede al database e restituisce oggetti

Si sono oggetti di dominio di business che prendono gli oggetti dell'elemento precedente e fare un po di logica con loro.

Se si unisce l'accesso ai dati con la logica del dominio aziendale, gli oggetti del dominio possono diventare difficili da testare. DI consente di iniettare i propri oggetti di accesso ai dati nel proprio dominio in modo da non dipendere dal database per test o possibilmente dimostrazioni (è stata eseguita una demo in cui alcuni dati sono stati estratti da xml anziché da un database).

Anche l'astrazione di componenti e quadri di terze parti come questo potrebbe essere d'aiuto.

Oltre all'esempio di prova, esistono alcuni punti in cui è possibile utilizzare DI tramite un approccio Design by Contract. Potresti trovare opportuno creare un motore di elaborazione di ordinamenti che richiami i metodi degli oggetti che stai iniettando in esso. Anche se non può veramente "processarlo", esegue i metodi che hanno un'implementazione diversa in ogni oggetto che fornisci.

Ho visto un esempio di ciò in cui ogni oggetto del dominio aziendale aveva una funzione "Salva" che veniva chiamata dopo essere stata iniettata nel processore. Il processore ha modificato il componente con le informazioni di configurazione e Salva gestito lo stato primario dell'oggetto. In sostanza, DI ha completato l'implementazione del metodo polimorfico degli oggetti conformi all'interfaccia.

6

Anche se non si modifica la struttura del programma durante le fasi di sviluppo, si scoprirà che è necessario accedere a diversi sottosistemi da diverse parti del programma. Con DI ciascuno dei tuoi corsi ha solo bisogno di chiedere servizi e sei libero di dover fornire tutto il cablaggio manualmente.

Questo mi aiuta molto a concentrarmi sull'interazione delle cose nel design del software e non su "chi ha bisogno di portare in giro perché qualcun altro ha bisogno di più tardi".

Inoltre, consente anche di risparmiare un sacco di codice di scrittura codice di lavoro. Ho bisogno di un singleton? Ho appena configurato una classe per essere uno. Posso testare con un "singleton"? Sì, posso ancora (dato che ho appena CONFIGURATO di esistere solo una volta, ma il test può creare un'istanza alternativa).

Ma, prima che stavo usando DI non ho davvero capito il suo valore, ma provarlo mi ha davvero aperto gli occhi: i miei progetti sono molto più orientati agli oggetti come prima. A proposito, con l'applicazione corrente NON faccio test unitari (male, male a me) ma ANCORA non potrei più vivere con DI. È molto più facile spostare le cose e mantenere le classi piccole e semplici.

+1

+1 per menzionare come i framework DI/IoC Container possono sostituire il malvagio pattern Singleton! – TrueWill

+0

La maggior parte del framework DI che vedo ha almeno 2000+ righe di codice, che sembra un sacco di codice. Inoltre, non sembra che tu possa usare il framework senza modificare il codice esistente. Nella tua esperienza, è facile scambiare un framework DI con un altro? – Boon

+0

@TrueWill Perché il singleton è malvagio mentre la versione DI è buono? – zehelvion

4

Iniezione delle dipendenze consente di testare specifiche unità di codice isolate.

Dire che ho una classe Foo ad esempio che prende un'istanza di una classe Bar nel suo costruttore. Uno dei metodi su Foo potrebbe verificare che un valore di proprietà di Bar sia uno che consenta l'esecuzione di un'altra elaborazione di Bar.

public class Foo 
{ 
    private Bar _bar; 

    public Foo(Bar bar) 
    { 
     _bar = bar; 
    } 

    public bool IsPropertyOfBarValid() 
    { 
     return _bar.SomeProperty == PropertyEnum.ValidProperty; 
    } 
} 

Ora diciamo che Bar viene istanziato e le sue proprietà sono impostati per i dati da qualche datasource in esso di costruttore. Come potrei andare a testare il metodo IsPropertyOfBarValid() di Foo (ignorando il fatto che questo è un esempio incredibilmente semplice)? Bene, Foo dipende dall'istanza di Bar inoltrata al costruttore, che a sua volta dipende dai dati dall'origine dati a cui sono impostate le proprietà. Quello che vorremmo fare è isolare Foo dalle risorse da cui dipende in modo da poterlo testare in isolamento

Qui è dove entra in gioco Dipendenza Iniezione. Quello che vogliamo è avere un modo di fingere un istanza di Bar passata a Foo tale da poter controllare le proprietà impostate su questo falso Bar e ottenere ciò che intendiamo fare, testare che l'implementazione di IsPropertyOfBarValid() fa ciò che ci aspettiamo che faccia, ovvero restituire true quando Bar.SomeProperty == PropertyEnum.ValidProperty e false per qualsiasi altro valore.

Esistono due tipi di oggetto falso, Mock e Stub. Gli stub forniscono input per l'applicazione in prova in modo che il test possa essere eseguito su qualcos'altro. Mock d'altra parte forniscono input per il test per decidere su pass \ fail.

Martin Fowler has a great article on the difference between Mocks and Stubs

1

penso che vale la pena DI utilizza quando si dispone di numerosi servizi/componenti le cui implementazioni deve essere selezionata in fase di esecuzione in base alla configurazione esterna. (Si noti che tale configurazione può assumere la forma di un file XML o una combinazione di annotazioni di codice e classi separate, scegliere ciò che è più conveniente.)

Altrimenti, vorrei semplicemente utilizzare un ServiceLocator, che è molto "più leggero" e più facile da capire rispetto a un intero quadro DI.

Per il test delle unità, preferisco utilizzare un'API di simulazione che può simulare oggetti su richiesta, anziché richiedere che vengano "iniettati" nell'unità testata da un test. Per Java, una libreria di questo tipo è la mia, JMockit.

+0

+1 per aver menzionato il servicelocator. Penso che a volte DI sembra eccessivo, quando le persone usano solo l'aspetto "posizione di servizio" di esso. –

0

Ho appena capito stasera. Per me, l'iniezione di dipendenza è un metodo per oggetti di istanza che richiedono un numero elevato di parametri per funzionare in un contesto specifico.

Quando utilizzare l'iniezione dipendente? È possibile utilizzare l'iniezione di dipendenza se si installa in modo statico un oggetto. Ad esempio, se si utilizza una classe che può convertire oggetti in file XML o JSON e se è necessario solo il file XML. Dovrai instanciare l'oggetto e configurare un sacco di cose se non usi l'iniezione di dipendenza.

Quando non si deve utilizzare l'impianto di depandancy? Se un oggetto è instanciato con i parametri di richiesta (dopo un modulo di invio), non si deve usare l'iniezione di depandancy perché l'oggetto non è instanciato in modo statico.

+0

Ho fatto questa domanda molti anni fa e da allora ho imparato molto. Quello che stai descrivendo sarebbe risolto bene usando un contenitore IoC e iniettando l'oggetto creato usando DI. Ad esempio, si configura il proprio oggetto "complicato" nel registro del contenitore IoC e si "richiede" un'istanza di ciò che si inietta nel codice dove è necessario. Sono d'accordo che quello è anche un motivo valido per usare DI. – CodeMonkey

9

DI è molto utile per il disaccoppiamento del sistema. Se tutto ciò che si sta usando per disaccoppiare l'implementazione del database dal resto dell'applicazione, allora l'applicazione è abbastanza semplice o è necessario fare molte più analisi sul dominio problematico e scoprire quali componenti all'interno del dominio del problema sono il più probabile per cambiare e i componenti all'interno del sistema che hanno una grande quantità di accoppiamento.

DI è molto utile quando si mira al riutilizzo del codice, alla versatilità e alla robustezza alle modifiche nel dominio del problema.

Quanto è rilevante per il progetto dipende dalla durata prevista del codice. A seconda del tipo di lavoro che stai facendo, riutilizzare zero da un progetto all'altro per la maggior parte del codice che stai scrivendo potrebbe essere abbastanza accettabile.

Un esempio per utilizzare l'utilizzo di DI consiste nella creazione di un'applicazione che può essere distribuita per diversi client utilizzando DI per iniettare personalizzazioni per il client, che potrebbe anche essere descritto come il modello di strategia GOF. Molti dei modelli GOF possono essere facilitati con l'uso di un framework DI.

DI è più rilevante per lo sviluppo di applicazioni Enterprise in cui si dispone di una grande quantità di codice, di requisiti aziendali complicati e di aspettative (o speranze) che il sistema verrà mantenuto per molti anni o decenni.

+0

È utile anche durante lo sviluppo rapido se si cerca flessibilità (perché si desidera condurre una sperimentazione). Puoi facilmente collegare diverse viste, strutture dati, menu, schemi di controllo e cosa no. Fondamentalmente (se ho capito e usato correttamente), consente di gestire le "dipendenze" in modo più flessibile e organizzato con meno rumore del codice della piastra della caldaia. Ovviamente potrebbe essere usato impropriamente e in qualche modo rendere il codice potenzialmente più complicato. – zehelvion