Al di fuori dei framework di iniezione di dipendenza, l'iniezione di dipendenza (tramite iniezione del costruttore o iniezione di setter) è quasi un gioco a somma zero: diminuisci l'accoppiamento tra l'oggetto A e la sua dipendenza B, ma ora qualsiasi oggetto che necessita di un'istanza di A ora deve costruisci anche l'oggetto B.
Hai leggermente ridotto l'accoppiamento tra A e B, ma hai ridotto l'incapsulamento di A e aumentato l'accoppiamento tra A e qualsiasi classe che deve costruire un'istanza di A, accoppiandoli anche alle dipendenze di A.
Quindi l'iniezione di dipendenza (senza un framework) è altrettanto dannosa in quanto utile.
Il costo aggiuntivo è spesso facilmente giustificabile, tuttavia: se il codice client sa di più su come costruire la dipendenza rispetto all'oggetto stesso, l'iniezione di dipendenza riduce davvero l'accoppiamento; ad esempio, uno Scanner non sa molto su come ottenere o costruire un flusso di input per analizzare l'input o da quale fonte il codice client vuole analizzare l'input, quindi l'iniezione del costruttore di un flusso di input è la soluzione ovvia.
Il test è un'altra giustificazione, al fine di poter utilizzare dipendenze simulate. Ciò dovrebbe significare l'aggiunta di un costruttore aggiuntivo utilizzato solo per il test che consente di iniettare dipendenze: se invece si modificano i costruttori per richiedere sempre l'iniezione di dipendenze, improvvisamente, è necessario conoscere le dipendenze delle dipendenze delle proprie dipendenze al fine di costruire le proprie dipendenze dirette e non è possibile svolgere alcun lavoro.
Può essere utile, ma dovresti sicuramente chiederti ogni dipendenza, il vantaggio del test vale il costo e voglio davvero deridere questa dipendenza durante il test?
Quando viene aggiunto un framework di iniezione delle dipendenze e la costruzione delle dipendenze viene delegata non al codice client ma al framework, l'analisi costi / benefici cambia notevolmente.
In un quadro di iniezione di dipendenza, i compromessi sono leggermente diversi; quello che stai perdendo iniettando una dipendenza è la capacità di sapere facilmente su quale implementazione fai affidamento e di spostare la responsabilità di decidere su quale dipendenza fai affidamento per un processo di risoluzione automatizzato (es. se abbiamo bisogno di un Foo @ Inject'ed , deve esserci qualcosa che @Provides Foo, e le cui dipendenze iniettate sono disponibili), o in alcuni file di configurazione di alto livello che prescrivono quale provider dovrebbe essere usato per ogni risorsa, o ad un ibrido dei due (ad esempio, potrebbe esserci essere un processo di risoluzione automatizzato per dipendenze che possono essere sovrascritte, se necessario, utilizzando un file di configurazione).
Come nell'iniezione del costruttore, penso che il vantaggio di farlo finisca, ancora una volta, molto simile al costo di farlo: non devi sapere chi sta fornendo i dati su cui fai affidamento e, se ci sono molteplici potenzialità fornitori, non è necessario conoscere l'ordine preferito per verificare la presenza di fornitori, assicurarsi che ogni posizione che necessita dei dati verifichi per tutti i potenziali fornitori, ecc., poiché tutto ciò è gestito ad alto livello dall'iniezione di dipendenza piattaforma.
Anche se personalmente non ho molta esperienza con i framework DI, la mia impressione è che forniscano maggiori vantaggi rispetto ai costi quando il mal di testa di trovare il fornitore corretto dei dati o del servizio di cui hai bisogno ha un costo superiore rispetto al mal di testa, quando qualcosa non riesce, di non sapere immediatamente a livello locale quale codice ha fornito i dati errati che hanno causato un successivo errore nel codice.
In alcuni casi, altri modelli che oscuravano le dipendenze (ad esempio i localizzatori di servizi) erano già stati adottati (e forse hanno anche dimostrato il loro valore) quando i framework DI sono apparsi sulla scena e i framework DI sono stati adottati perché offrivano alcuni vantaggi competitivi, come richiedere meno codice plateplate, o potenzialmente facendo di meno per oscurare il provider di dipendenza quando diventa necessario determinare quale provider è effettivamente in uso.