Qual è la differenza tra i modelli di iniezione delle dipendenze e localizzatore di servizio?

Entrambi i modelli sembrano un’implementazione del principio di inversione del controllo. Cioè, che un object non dovrebbe sapere come build le sue dipendenze.

Iniezione di dipendenza (DI) sembra utilizzare un costruttore o un setter per “iniettare” le sue dipendenze.

Esempio di utilizzo di Iniezione costruttore:

//Foo Needs an IBar public class Foo { private IBar bar; public Foo(IBar bar) { this.bar = bar; } //... } 

Service Locator sembra utilizzare un “contenitore”, che collega le sue dipendenze e dà la sua barra.

Esempio di utilizzo di un localizzatore di servizi:

 //Foo Needs an IBar public class Foo { private IBar bar; public Foo() { this.bar = Container.Get(); } //... } 

Poiché le nostre dipendenze sono solo oggetti stessi, queste dipendenze hanno dipendenze, che hanno ancora più dipendenze e così via e così via. Così è nato il contenitore Inversion of Control (o DI Container). Esempi: Castle Windsor, Ninject, Structure Map, Spring, ecc.)

Ma un contenitore IOC / DI sembra esattamente come un localizzatore di servizi. Lo chiama un contenitore DI un brutto nome? Un container IOC / DI è solo un altro tipo di localizzatore di servizi? È la sfumatura nel fatto che usiamo i contenitori DI per lo più quando abbiamo molte dipendenze?

La differenza può sembrare lieve, ma anche con ServiceLocator, la class è ancora responsabile della creazione delle sue dipendenze. Usa solo il localizzatore di servizi per farlo. Con DI, alla class vengono date le sue dipendenze. Non sa, né importa da dove vengono. Un risultato importante di questo è che l’esempio DI è molto più facile da testare l’unità – perché è ansible passarlo a implementazioni fittizie dei suoi oggetti dipendenti. Potresti combinare i due – e iniettare il localizzatore di servizio (o una fabbrica), se lo volessi.

Quando si utilizza un localizzatore di servizi, ogni class avrà una dipendenza dal proprio localizzatore di servizi. Questo non è il caso dell’iniezione di dipendenza. Generalmente, l’iniettore delle dipendenze verrà chiamato una sola volta all’avvio per iniettare dipendenze in alcune classi principali. Le classi di questa class principale dipendono in modo ricorsivo in modo ricorsivo delle loro dipendenze, fino a quando non si ottiene un grafico completo degli oggetti.

Un buon confronto: http://martinfowler.com/articles/injection.html

Se il tuo iniettore di dipendenze sembra un localizzatore di servizi, dove le classi chiamano direttamente l’iniettore, probabilmente non è un iniettore di dipendenze, ma piuttosto un localizzatore di servizi.

I locatori di servizi nascondono le dipendenze: non è ansible distinguere guardando un object se colpisce un database o meno (ad esempio) quando ottiene le connessioni da un localizzatore. Con l’iniezione di dipendenza (almeno l’iniezione del costruttore) le dipendenze sono esplicite.

Inoltre, i localizzatori di servizi interrompono l’incapsulamento perché forniscono un punto di accesso globale alle dipendenze di altri oggetti. Con il localizzatore di servizi, come con qualsiasi singolo singleton :

diventa difficile specificare le condizioni pre e post per l’interfaccia dell’object client, poiché il funzionamento della sua implementazione può essere intromesso dall’esterno.

Con l’iniezione di dipendenza, una volta specificate le dipendenze di un object, esse sono sotto il controllo dell’object stesso.

Martin Fowler afferma :

Con il localizzatore di servizi, la class dell’applicazione richiede esplicitamente un messaggio al localizzatore. Con l’iniezione non c’è una richiesta esplicita, il servizio appare nella class dell’applicazione – da qui l’inversione del controllo.

In breve: Service Locator e Dependency Injection sono solo implementazioni di Dependency Inversion Principle.

Il principio importante è “dipende dalle astrazioni, non dalle concrezioni”. Questo renderà il tuo software progettato “liberamente accoppiato”, “estensibile”, “flessibile”.

Puoi usare quello che si adatta meglio alle tue esigenze. Per una grande applicazione, avendo una base di codice enorme, è meglio usare un Localizzatore di servizio, perché la Dipendenza dell’iniezione richiederebbe più modifiche al codice base.

Puoi controllare questo post: Dependency Inversion: Service Locator o Dependency Injection

Anche il classico: Inversion of Control Containers e il pattern In Dependency Injection di Martin Fowler

Progettare classi riutilizzabili di Ralph E. Johnson e Brian Foote

Tuttavia, quello che mi ha aperto gli occhi è stato: ASP.NET MVC: Resolve o Inject? Questo è il problema … di Dino Esposito

Una class che utilizza il costruttore DI indica di consumare codice che ci sono dipendenze da soddisfare. Se la class utilizza la SL internamente per recuperare tali dipendenze, il codice che consuma non è a conoscenza delle dipendenze. Questo può sembrare superficiale, ma in realtà è utile sapere di eventuali dipendenze esplicite. È meglio da una vista architettonica. E quando si esegue il test, è necessario sapere se una class ha bisogno di determinate dipendenze e configurare la SL per fornire versioni false appropriate di tali dipendenze. Con DI, basta passare i falsi. Non un’enorme differenza, ma è lì.

DI e SL possono lavorare insieme, però. È utile avere una posizione centrale per le dipendenze comuni (ad es. Impostazioni, logger, ecc.). Data una class che utilizza tali servizi, è ansible creare un costruttore “reale” che riceve i deps e un costruttore predefinito (nessun parametro) che recupera dalla SL e inoltra al costruttore “reale”.

EDIT: e, ovviamente, quando si utilizza la SL, si sta introducendo un certo accoppiamento con quel componente. Il che è ironico, poiché l’idea di tale funzionalità è incoraggiare le astrazioni e ridurre l’accoppiamento. Le preoccupazioni possono essere bilanciate, e dipende da quanti posti avresti bisogno di usare la SL. Se fatto come suggerito sopra, solo nel costruttore di classi predefinito.

Penso che i due lavori insieme.

Iniezione di dipendenza significa che si inserisce una class / interfaccia dipendente in una class che consuma (in genere nel costruttore). Questo disaccoppia le due classi tramite un’interfaccia e significa che la class consumatrice può lavorare con molti tipi di implementazioni di “dipendenza iniettata”.

Il ruolo del localizzatore di servizi è di mettere insieme la tua implementazione. Si imposta un localizzatore di servizi tramite alcune cinghie di avvio all’inizio del programma. Bootstrap è il processo di associazione di un tipo di implementazione a un particolare astratto / interfaccia. Che viene creato per te in fase di esecuzione. (basato su configurazione o bootstrap). Se non avessi implementato l’integrazione delle dipendenze, sarebbe molto difficile utilizzare un localizzatore di servizi o un container IOC.

Entrambi sono tecniche di implementazione di IoC. Esistono anche altri pattern che implementano Inversion of Control:

  • modello di fabbrica
  • localizzatore di servizi
  • iniezione di dipendenza (iniezione costruttore, iniezione parametri (se non richiesta), iniezione setter di iniezione interfaccia) …

Service locator e DI sembrano più simili, entrambi utilizzano il contenitore per definire le dipendenze, che mappano l’astrazione all’implementazione concreta.

La differenza principale è il modo in cui si trovano le dipendenze, nel codice del client Location Service si richiedono le dipendenze, in DI si usa il contenitore per creare tutti gli oggetti e si inietta la dipendenza come parametri del costruttore (o proprietà).

Nel mio ultimo progetto li uso entrambi. Uso l’iniezione di dipendenza per la testabilità dell’unità. Uso il localizzatore di servizi per hide l’implementazione e dipendere dal mio contenitore IoC. e sì! Una volta che usi uno dei contenitori IoC (Unity, Ninject, Windsor Castle), ne fai affidamento. E una volta che è obsoleto o per qualche motivo se si vorrà scambiarlo, si dovrà / potrebbe aver bisogno di cambiare la propria implementazione – almeno la composizione root. Ma il localizzatore di servizi astrae quella fase.

Come non dovresti dipendere dal tuo contenitore IoC? O dovrai avvolgerlo da te (che è una ctriggers idea) o utilizzare Service Locator per configurare il tuo contenitore IoC. Quindi dirai al localizzatore di servizi quale interfaccia hai bisogno e chiamerà il contenitore IoC configurato per recuperare quell’interfaccia.

Nel mio caso, utilizzo ServiceLocator che è un componente framework. E usa Unity per il contenitore IoC. Se in futuro avrò bisogno di scambiare il mio contenitore IoC con Ninject tutto quello che devo fare è che devo configurare il mio localizzatore di servizio per usare Ninject invece di Unity. Facile migrazione

Ecco un grande articolo spiega questo scenario; http://www.johandekoning.nl/index.php/2013/03/03/dont-wrap-your-ioc-container/

Una ragione per aggiungere, ispirata da un aggiornamento della documentazione che abbiamo scritto per il progetto MEF la scorsa settimana (aiuto a build MEF).

Una volta che un’app è composta da potenzialmente migliaia di componenti, può essere difficile determinare se un particolare componente può essere istanziato correttamente. Con “istanziato correttamente”, intendo che in questo esempio basato sul componente Foo , sarà disponibile un’istanza di IBar e che il componente che lo fornisce:

  • hanno le sue dipendenze richieste,
  • non essere coinvolto in alcun ciclo di dipendenza non valido, e
  • nel caso di MEF, essere fornito con una sola istanza.

Nel secondo esempio che hai dato, dove il costruttore va al contenitore IoC per recuperare le sue dipendenze, l’unico modo per verificare che un’istanza di Foo possa essere istanziata correttamente con la configurazione di runtime effettiva della tua app è effettivamente costruirlo .

Questo ha tutti i tipi di effetti collaterali imbarazzanti al momento del test, perché il codice che funzionerà in runtime non funzionerà necessariamente sotto un’imbracatura di test. I mazzi non lo faranno, perché la vera configurazione è la cosa che dobbiamo testare, non una configurazione in fase di test.

La radice di questo problema è la differenza già richiamata da @Jon: l’iniezione delle dipendenze tramite il costruttore è dichiarativa, mentre la seconda versione utilizza il modello imperativo di localizzazione del servizio.

Un contenitore IoC, se usato con attenzione, può analizzare in modo statico la configurazione runtime della tua app senza creare effettivamente alcuna istanza dei componenti coinvolti. Molti contenitori popolari forniscono alcune variazioni di questo; Microsoft.Composition , che è la versione di MEF per il targeting di .NET 4.5 e applicazioni in stile Metro, fornisce un esempio di CompositionAssert nella documentazione wiki. Usandolo, puoi scrivere codice come:

  // Whatever you use at runtime to configure the container var container = CreateContainer(); CompositionAssert.CanExportSingle(container); 

(Vedi questo esempio ).

Verificando le Composition Root della tua applicazione al momento del test, è ansible rilevare alcuni errori che potrebbero altrimenti passare attraverso i test più avanti nel processo.

Spero che questa sia un’aggiunta interessante a questo insieme altrimenti esaustivo di risposte sull’argomento!

Nota: non sto esattamente rispondendo alla domanda. Tuttavia, ritengo che ciò possa essere utile per i nuovi studenti del modello di Iniezione delle Dipendenze che sono confusi a riguardo con il pattern di identificazione del servizio (anti-) che capita di imbattersi in questa pagina.

Conosco la differenza tra il Localizzatore di servizi (sembra essere considerato un anti-pattern ora) e gli schemi di Iniezione di dipendenza e posso comprendere esempi concreti di ciascun modello, ma sono stato confuso da esempi che mostrano un locator di servizio all’interno del costruttore (supponiamo che noi facendo l’iniezione del costruttore).

“Service Locator” è spesso usato sia come nome di un pattern, sia come nome per riferirsi all’object (supponiamo anche) usato in quel pattern per ottenere oggetti senza usare il nuovo operatore. Ora, lo stesso tipo di object può essere usato anche nella composizione della radice per eseguire l’iniezione di dipendenza, ed è qui che entra in gioco la confusione.

Il punto è che è ansible che si stia utilizzando un object del servizio di localizzazione all’interno di un costruttore DI, ma non si sta utilizzando il modello “Service Locator”. È meno confuso se lo si fa riferimento come object contenitore IoC, come si può intuire che essenzialmente fanno la stessa cosa (correggimi se sbaglio).

Che si tratti di un localizzatore di servizi (o solo di un localizzatore) o di un contenitore IoC (o solo di un contenitore) non fa alcuna differenza, come si può intuire, poiché probabilmente si riferiscono alla stessa astrazione (correggimi se ho torto ). E ‘solo che chiamandolo “localizzatore di servizi” si suggerisce che si sta utilizzando l’anti-pattern di Service Locator insieme al pattern di Iniezione di dipendenza.

IMHO, nominandolo ‘localizzatore’ invece di ‘posizione’ o ‘localizzazione’, può anche far pensare a volte che il localizzatore di servizio in un articolo si riferisca al contenitore di Service Locator, e non al pattern di localizzazione del servizio (anti-) , specialmente quando c’è un modello correlato chiamato Iniezione di dipendenza e non Iniettore di dipendenza.

In questo caso troppo semplificato non c’è differenza e possono essere usati in modo intercambiabile. Tuttavia, i problemi del mondo reale non sono così semplici. Supponiamo che la stessa class Bar abbia un’altra dipendenza chiamata D. In tal caso il localizzatore di servizi non sarebbe in grado di risolvere quella dipendenza e si dovrebbe istanziarlo all’interno della class D; perché è responsabilità delle tue classi istanziare le loro dipendenze. Andrebbe anche peggio se la class D avesse altre dipendenze e nelle situazioni del mondo reale di solito diventa ancora più complicata di così. In tali scenari, DI è una soluzione migliore di ServiceLocator.

Qual è la differenza (se esiste) tra l’iniezione delle dipendenze e il localizzatore di servizio? Entrambi i modelli sono in grado di implementare il principio di inversione delle dipendenze. Il pattern Locator del servizio è più facile da utilizzare in una base di codice esistente poiché rende il design generale più flessibile senza imporre modifiche all’interfaccia pubblica. Per lo stesso motivo, il codice basato sul modello di Service Locator è meno leggibile rispetto al codice equivalente basato su Dependency Injection.

Il modello Dipendenza Iniezione rende chiaro fin dalla firma quali dipendenze avrà una class (o un metodo). Per questo motivo, il codice risultante è più pulito e più leggibile.