L'inversione di dipendenza dovrebbe essere utilizzata solo con gli adattatori ovunque?

4

Comprendo lo scopo di DI è che posso facilmente scambiare un'implementazione di livello inferiore. Ma costringe l'astrazione di livello inferiore a essere definita all'interno del livello più alto.

Un livello inferiore diventa dipendente dall'astrazione definita nel livello superiore e non può essere utilizzato senza di esso. Ma cosa succederebbe se volessi riutilizzare la mia classe Logger di livello inferiore in un'altra applicazione?

Devo usare Adapter ovunque con DI? Nel mio esempio, Adapter potrebbe implementare l'interfaccia ILogger dal codice di livello superiore e reindirizzare le chiamate alla classe Logger che ora diventa riutilizzabile e indipendente dalla mia applicazione.

È un buon approccio?

    
posta Vlad 05.06.2015 - 12:34
fonte

3 risposte

1

Qualche tempo è passato e ora penso di poter rispondere da solo.

  1. Non ha senso creare un adattatore quando due classi interagenti si trovano nella stessa dll. In tal caso, rende il codice più complicato e difficile per il refactoring ma non offre alcun vantaggio. Se vuoi riutilizzare alcune funzionalità, devi comunque fare riferimento all'intera DLL, quindi non preoccuparti.

  2. Ogni componente (indipendentemente dal fatto che sia di livello inferiore o superiore) dovrebbe dipendere dalle astrazioni (con solo i metodi di cui ha bisogno) che possono essere dichiarati accanto o nella stessa dll (se sono condivisi tra più componenti ).

  3. Dovrebbe esserci un sistema speciale di "configurazione" che fornisce adattatori e fabbriche. Poiché nessuna classe è a conoscenza dell'implementazione delle sue dipendenze, abbiamo bisogno di questo sistema per costruire oggetti e connettere tutte le parti della soluzione.

risposta data 13.06.2015 - 09:06
fonte
4

Sei molto confuso.

A lower level becomes dependent on the abstraction defined in the higher level

No, non lo è. Dipende solo dall'astrazione che ha definito stesso . Ad esempio, un TaxAuditImpl potrebbe dipendere dall'interfaccia TaxAuditor che soddisfa. Tuttavia, non dipende dal SuperDuperPersonalFinanceManager che usa il TaxAuditor . Tutto rimane piacevolmente al suo livello.

Certo, il FinanceManager fa dipende dal% di livello inferioreTaxAuditor, ma va bene - non può molto usarlo senza dipendere da esso. E l'iniezione di dipendenza serve a ridurre questo tipo di dipendenza, perché FinanceManager non deve conoscere il Impl , solo l'interfaccia.

    
risposta data 05.06.2015 - 12:45
fonte
2

But it forces the lower level abstraction to be defined inside the higher level.

No, non lo fa rispettare. L '"astrazione di livello inferiore" (l'interfaccia, come ILogger nel tuo esempio) può essere definita al di fuori del componente "livello inferiore" e "livello superiore", può risiedere in una terza DLL indipendente che serve solo allo scopo di fornire le interfacce. Questo componente non fa parte né del componente di livello inferiore né di quello di livello superiore.

In realtà, ho scritto "può", perché non è l'unica alternativa possibile al design. Le altre due alternative (quella che hai suggerito: ILogger nel componente di livello superiore e quella suggerita da @KilianFoth, ILogger come componente del componente Logger), sono anche approcci validi, con il vantaggio che hai bisogno di meno DLL / componenti, ma anche alcuni inconvenienti relativi alle dipendenze o alle restrizioni risultanti sulla riusabilità. Mettere l'interfaccia ILogger nella DLL Logger impone che il tuo "componente di livello superiore" debba ancora dipendere dal componente Logger di livello inferiore, ovviamente, ma ti lascia comunque l'opzione di sostituire l'oggetto Logger nel tuo componente di livello superiore da parte di un "logger di test" per scopi di test unitari, a patto che il codice del test non abbia il problema di avere una dipendenza dal link alla DLL del logger.

A lower level becomes dependent on the abstraction defined in the higher level and can't be used without it.

No, diventa dipendente dal componente dell'interfaccia. Non è possibile utilizzare il logger senza quel componente di interfaccia, ovviamente. Ma puoi riutilizzare la DLL del logger in combinazione con la DLL di ILogger in un progetto completamente separato.

In my example Adapter could implement ILogger interface from the higher-level code and reroute calls to the Logger class which now becomes reusable and independent from my application.

Lo scenario di utilizzo tipico di un adattatore è quando si hanno interfacce incompatibili e non si può facilmente modificare il codice esistente. Ad esempio, dove il componente di livello superiore BusinessCalculator si aspetta un% co_de injected (un'interfaccia, forse definita nella DLL in cui BLogger vive, con alcuni requisiti speciali). Il tuo componente BusinessCalculator standard che hai già utilizzato in altri cinque progetti e per il quale non cambierai il design, si trova nella DLL "Logger riutilizzabile" e fornisce solo un'interfaccia Logger incompatibile (forse definita direttamente nel tuo Logger DLL, forse definito in una interfaccia separata DLL). Quindi è necessaria una classe adattatore che esegue il mapping delle chiamate ILogger a BLogger .

Con quest'ultimo design, puoi in effetti separare completamente i componenti ILogger e BusinessCalculator , solo l'adattatore dipenderà dalle DLL in cui Logger e BLogger sono definite. Tecnicamente, non è nemmeno più chiaro quale dei due sia il componente più "di livello superiore" o "di livello inferiore". Lo svantaggio è il sovraccarico aggiuntivo per la gestione di tutte quelle interfacce e componenti diversi.

    
risposta data 13.06.2015 - 10:00
fonte

Leggi altre domande sui tag