it-swarm.it

Cos'è l'iniezione di dipendenza?

Ci sono state diverse domande già postate con domande specifiche su injection injection , come quando usarlo e quali framework ci sono per esso. Però,

Cos'è l'iniezione di dipendenza e quando/perché dovrebbe o non dovrebbe essere usata?

2811
AR.

Fondamentalmente, invece di avere gli oggetti che creano una dipendenza o di chiedere a un oggetto factory di crearne uno per loro, si passa esternamente le dipendenze necessarie all'oggetto e si crea il problema di qualcun altro. Questo "qualcuno" è o un oggetto più in alto sul grafico delle dipendenze, o un injector delle dipendenze (framework) che costruisce il grafico delle dipendenze. Una dipendenza mentre la sto usando qui è qualsiasi altro oggetto a cui l'oggetto corrente deve avere un riferimento.

Uno dei principali vantaggi dell'iniezione di dipendenza è che può rendere più semplici i test. Supponiamo di avere un oggetto che nel suo costruttore fa qualcosa del tipo:

public SomeClass() {
    myObject = Factory.getObject();
}

Questo può essere problematico quando tutto ciò che si vuole fare è eseguire alcuni test unitari su SomeClass, specialmente se myObject è qualcosa che fa un accesso complesso al disco o alla rete. Quindi ora stai cercando di deridere myObject ma anche in qualche modo intercettando la chiamata factory. Difficile. Invece, passare l'oggetto come argomento al costruttore. Ora hai spostato il problema altrove, ma il test può diventare molto più semplice. Basta creare un myObject fittizio e inoltrarlo. Il costruttore ora assomiglia un po 'a:

public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

Questo è uno stile di iniezione delle dipendenze - tramite il costruttore. Sono possibili diversi meccanismi. 

  • Come notato nei commenti, un'alternativa comune è definire un costruttore del nulla-fare e avere le dipendenze iniettate tramite i setter di proprietà (h/t @MikeVella). 
  • Martin Fowler documenta una terza alternativa (h/t @MarcDix), dove le classi implementano esplicitamente un'interfaccia per le dipendenze che desiderano iniettare.

Quando non si utilizza l'iniezione di dipendenza (come nelle classi che fanno troppo lavoro nei loro costruttori, ecc.), Tende a diventare molto più difficile isolare i componenti nei test unitari. 

Nel 2013, quando ho scritto questa risposta, questo era uno dei temi principali su Google Testing Blog . Questo rimane il più grande vantaggio per me, poiché potresti non aver sempre bisogno della flessibilità extra nella progettazione del tuo run-time (ad esempio, per localizzatore di servizi o modelli simili), ma spesso devi essere in grado di isolare le tue classi durante i test.

1764
wds

La migliore definizione che ho trovato finora è quella di James Shore

"Dependency Injection" è un valore di 25 dollari termine per un concetto di 5 centesimi. [...] Iniezione di dipendenza significa dare un oggetto le sue variabili di istanza. [...].

C'è un articolo di Martin Fowler che potrebbe rivelarsi utile.

L'iniezione di dipendenza fornisce fondamentalmente gli oggetti di cui un oggetto ha bisogno (le sue dipendenze) invece di costruirli da sé. È una tecnica molto utile per i test, dal momento che consente alle dipendenze di essere derisi o eliminati.

Le dipendenze possono essere iniettate in oggetti con molti mezzi (come iniezione del costruttore o iniezione setter). Si può persino usare strutture specializzate per l'iniezione delle dipendenze (ad esempio Spring) per farlo, ma certamente non sono necessarie. Non hai bisogno di quei quadri per avere un'iniezione di dipendenza. Istanziare e passare oggetti (dipendenze) in modo esplicito è un'iniezione altrettanto buona che un'iniezione per quadro.

2167
Thiago Arrais

Ho trovato questo divertente esempio in termini di loose coupling :

Qualsiasi applicazione è composta da molti oggetti che collaborano tra loro per eseguire alcune cose utili. Tradizionalmente ogni oggetto è responsabile di ottenere i propri riferimenti agli oggetti dipendenti (dipendenze) con cui collabora. Questo porta a classi altamente accoppiate e codice difficile da testare.

Ad esempio, considera un oggetto Car.

A Car dipende da ruote, motore, carburante, batteria, ecc. Per funzionare. Tradizionalmente definiamo la marca di tali oggetti dipendenti insieme alla definizione dell'oggetto Car.

Without Dependency Injection (DI):

class Car{
  private Wheel wh = new NepaliRubberWheel();
  private Battery bt = new ExcideBattery();

  //The rest
}

Qui, l'oggetto Carè responsabile della creazione degli oggetti dipendenti.

Cosa succede se vogliamo cambiare il tipo del suo oggetto dipendente - diciamo Wheel - dopo le forature NepaliRubberWheel() iniziali? Abbiamo bisogno di ricreare l'oggetto Car con la sua nuova dipendenza dire ChineseRubberWheel(), ma solo il produttore Car può farlo.

Allora cosa ci fa lo Dependency Injection per ...?

Quando si utilizza l'iniezione di dipendenza, agli oggetti vengono assegnate le loro dipendenze in fase di esecuzione anziché in fase di compilazione (tempo di produzione dell'auto) . Così ora possiamo cambiare Wheel ogni volta che vogliamo. Qui, dependency (wheel) può essere iniettato in Car in fase di esecuzione.

Dopo aver utilizzato l'iniezione di dipendenza:

Qui, stiamo iniettando le dependencies (Ruota e batteria) in fase di runtime. Da qui il termine: Iniezione di dipendenza. 

class Car{
  private Wheel wh = [Inject an Instance of Wheel (dependency of car) at runtime]
  private Battery bt = [Inject an Instance of Battery (dependency of car) at runtime]
  Car(Wheel wh,Battery bt) {
      this.wh = wh;
      this.bt = bt;
  }
  //Or we can have setters
  void setWheel(Wheel wh) {
      this.wh = wh;
  }
}

Fonte: Comprensione dell'iniezione delle dipendenze

554
gtiwari333

Dipendenza L'iniezione è una pratica in cui gli oggetti sono progettati in modo da ricevere istanze degli oggetti da altri pezzi di codice, invece di costruirli internamente. Ciò significa che qualsiasi oggetto che implementa l'interfaccia richiesta dall'oggetto può essere sostituito senza modificare il codice, il che semplifica il test e migliora il disaccoppiamento.

Ad esempio, considera questi clases:

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

In questo esempio, l'implementazione di PersonService::addManager e PersonService::removeManager richiederebbe un'istanza di GroupMembershipService per poter funzionare. Senza Iniezione di dipendenza, il modo tradizionale per farlo sarebbe istanziare un nuovo GroupMembershipService nel costruttore di PersonService e usare quell'attributo di istanza in entrambe le funzioni. Tuttavia, se il costruttore di GroupMembershipService ha più cose che richiede, o peggio ancora, ci sono alcuni "setter" di inizializzazione che devono essere chiamati su GroupMembershipService, il codice cresce piuttosto rapidamente, e PersonService ora non dipende solo da GroupMembershipService ma anche tutto il resto che GroupMembershipService dipende. Inoltre, il collegamento a GroupMembershipService è codificato in PersonService, il che significa che non è possibile "inventare" un GroupMembershipService a scopo di test o utilizzare un modello di strategia in diverse parti dell'applicazione. 

Con Iniezione delle dipendenze, invece di istanziare GroupMembershipService all'interno PersonService, dovresti passarlo al costruttore PersonService, oppure aggiungere una proprietà (getter e setter) per impostarne un'istanza locale. Ciò significa che PersonService non deve più preoccuparsi di come creare un GroupMembershipService, accetta solo quelli che ha dato e lavora con loro. Ciò significa anche che tutto ciò che è una sottoclasse di GroupMembershipService, o implementa l'interfaccia GroupMembershipService può essere "iniettato" nella PersonService, e PersonService non ha bisogno di sapere della modifica.

241
Adam Ness

La risposta accettata è buona, ma vorrei aggiungere che DI è molto simile al classico che evita costanti hardcoded nel codice. 

Quando si usano alcune costanti come il nome di un database, lo si sposta rapidamente dall'interno del codice in qualche file di configurazione e si passa una variabile che contiene quel valore nel punto in cui è necessario. La ragione per farlo è che queste costanti di solito cambiano più frequentemente rispetto al resto del codice. Ad esempio se desideri testare il codice in un database di test. 

DI è analogo a questo nel mondo della programmazione orientata agli oggetti. I valori lì invece dei costanti costanti sono oggetti interi, ma la ragione per spostare il codice che li crea fuori dal codice di classe è simile - gli oggetti cambiano più frequentemente del codice che li usa. Un caso importante in cui tale cambiamento è necessario sono i test.

155
zby

Proviamo un semplice esempio con Car e Engine classes, qualsiasi auto ha bisogno di un motore per andare ovunque, almeno per ora. Quindi sotto come apparirà il codice senza iniezione di dipendenza.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

E per istanziare la classe Car useremo il prossimo codice:

Car car = new Car();

Il problema con questo codice che abbiamo strettamente accoppiato a GasEngine e se decidiamo di cambiarlo in ElectricityEngine, allora dovremo riscrivere la classe Car. E più grande è l'applicazione, più problemi e mal di testa dovremo aggiungere e usare un nuovo tipo di motore. 

In altre parole, con questo approccio, la nostra classe Car di alto livello dipende dalla classe GasEngine di livello inferiore che viola il principio di inversione delle dipendenze (DIP) da SOLID. Il DIP suggerisce che dovremmo dipendere dalle astrazioni, non dalle lezioni concrete. Per soddisfare questo, introduciamo l'interfaccia IEngine e riscriviamo il codice come di seguito:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Ora la nostra classe Car dipende solo dall'interfaccia IEngine, non da un'implementazione specifica del motore. Ora, l'unico trucco è come creare un'istanza della macchina e dargli una classe concreta di motore come GasEngine o ElectricityEngine. Ecco dove Iniezione delle dipendenze entra. 

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Qui fondamentalmente iniettiamo (passiamo) la nostra dipendenza (istanza del motore) al costruttore di automobili. Così ora le nostre classi hanno un accoppiamento lento tra gli oggetti e le loro dipendenze, e possiamo facilmente aggiungere nuovi tipi di motori senza modificare la classe Car.

Il vantaggio principale di Dependency Injection che le classi sono più liberamente accoppiate, perché non hanno dipendenze hard-coded. Questo segue il principio di inversione della dipendenza, che è stato menzionato sopra. Invece di fare riferimento a specifiche implementazioni, le classi richiedono astrazioni (di solito interfacce ) che vengono fornite loro quando la classe è costruita.

Quindi alla fine Iniezione delle dipendenze è solo una tecnica per realizzare un accoppiamento lento tra oggetti e le loro dipendenze . Piuttosto che creare direttamente delle dipendenze di cui la classe ha bisogno in Per eseguire le sue azioni, le dipendenze sono fornite alla classe (il più delle volte) tramite l'iniezione del costruttore.

Inoltre, quando abbiamo molte dipendenze, è molto buona pratica usare i contenitori di Inversion of Control (IoC) che possiamo dire quali interfacce dovrebbero essere mappate su quali implementazioni concrete per tutte le nostre dipendenze e possiamo far sì che risolva quelle dipendenze per noi quando costruisce il nostro oggetto. Ad esempio, potremmo specificare nella mappatura per il contenitore IoC che la dipendenza IEngine deve essere mappata alla classe GasEngine e quando chiediamo al contenitore IoC un'istanza della nostra Car class , costruirà automaticamente la nostra Car class con una dipendenza GasEngine passata. 

AGGIORNAMENTO: Ho seguito di recente un corso su EF Core da Julie Lerman e mi è piaciuta anche la sua breve definizione su DI.

L'iniezione di dipendenza è uno schema che consente alla tua applicazione di iniettare oggetti al volo per le classi che ne hanno bisogno, senza forzare quelli classi per essere responsabili di quegli oggetti. Permette al tuo codice di essere più liberamente accoppiati e Entity Framework Core si collega a questo stesso sistema di servizi.

103
user2771704

Immaginiamo che tu voglia andare a pescare:

  • Senza l'iniezione di dipendenza, è necessario prendersi cura di tutto da soli. Devi trovare una barca, comprare una canna da pesca, cercare esche, ecc. È possibile, certo, ma ti mette molta responsabilità. In termini di software, significa che devi eseguire una ricerca per tutte queste cose.

  • Con l'iniezione di dipendenza, qualcun altro si prende cura di tutta la preparazione e mette a disposizione l'attrezzatura necessaria. Riceverai ("essere iniettato") la barca, la canna da pesca e l'esca - tutto pronto per l'uso.

102
Olivier Liechti

Questo è la spiegazione più semplice su Dependency Injection e Dependency Injection Container che abbia mai visto:

Senza iniezione di dipendenza

  • L'applicazione ha bisogno di Foo (ad esempio un controller), quindi:
  • L'applicazione crea Foo
  • L'applicazione chiama Foo
    • Foo ha bisogno di Bar (ad esempio un servizio), quindi:
    • Foo crea Bar
    • Foo chiama Bar
      • Bar ha bisogno di Bim (un servizio, un repository, ...), quindi:
      • Bar crea Bim
      • Bar fa qualcosa

Con iniezione di dipendenza

  • L'applicazione ha bisogno di Foo, che ha bisogno di Bar, che ha bisogno di Bim, quindi:
  • L'applicazione crea Bim
  • L'applicazione crea una barra e la dà Bim
  • L'applicazione crea Foo e dà Bar
  • L'applicazione chiama Foo
    • Foo chiama Bar
      • Bar fa qualcosa

Utilizzo di un contenitore per iniezione di dipendenza

  • L'applicazione ha bisogno di Foo così:
  • L'applicazione ottiene Foo dal contenitore, quindi:
    • Il contenitore crea Bim
    • Il contenitore crea una barra e la dà Bim
    • Container crea Foo e gli dà Bar
  • L'applicazione chiama Foo
    • Foo chiama Bar
      • Bar fa qualcosa

Dipendenza Iniezione e dipendenza I contenitori di iniezione sono cose diverse:

  • La dipendenza dall'iniezione è un metodo per scrivere un codice migliore
  • un contenitore DI è uno strumento per aiutare a iniettare dipendenze

Non hai bisogno di un contenitore per fare l'iniezione di dipendenza. Tuttavia un contenitore può aiutarti.

86
Trix

Non "iniezione di dipendenza" significa solo l'uso di costruttori parametrizzati e di setter pubblici?

L'articolo di James Shore mostra i seguenti esempi per il confronto .

Costruttore senza iniezione di dipendenza:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example() { 
    myDatabase = new DatabaseThingie(); 
  } 

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
} 

Costruttore con iniezione di dipendenza:

public class Example { 
  private DatabaseThingie myDatabase; 

  public Example(DatabaseThingie useThisDatabaseInstead) { 
    myDatabase = useThisDatabaseInstead; 
  }

  public void doStuff() { 
    ... 
    myDatabase.getData(); 
    ... 
  } 
}
49
JaneGoodall

Per rendere il concetto di dipendenza da iniezione semplice da capire. Prendiamo un esempio di pulsante di commutazione per attivare (acceso/spento) una lampadina.

Senza iniezione di dipendenza

Switch ha bisogno di sapere in anticipo a quale lampadina sono collegato (dipendenza hard-coded). Così,

Switch -> Switch PermanentBulb // è collegato direttamente alla lampadina permanente, test non è possibile facilmente

 

Switch(){
PermanentBulb = new Bulb();
PermanentBulb.Toggle();
}

Con iniezione di dipendenza

Lo switch sa solo che ho bisogno di accendere/spegnere qualsiasi Lampadina passata a me. Così,

Switch -> Bulb1 OR Bulb2 OR NightBulb (dipendenza iniettata)

 

Switch(AnyBulb){ //pass it whichever bulb you like
AnyBulb.Toggle();
}

Modifica James Esempio per interruttore e lampadina:

public class SwitchTest { 
  TestToggleBulb() { 
    MockBulb mockbulb = new MockBulb(); 

    // MockBulb is a subclass of Bulb, so we can 
    // "inject" it here: 
    Switch switch = new Switch(mockBulb); 

    switch.ToggleBulb(); 
    mockBulb.AssertToggleWasCalled(); 
  } 
}

public class Switch { 
  private Bulb myBulb; 

  public Switch() { 
    myBulb = new Bulb(); 
  } 

  public Switch(Bulb useThisBulbInstead) { 
    myBulb = useThisBulbInstead; 
  } 

  public void ToggleBulb() { 
    ... 
    myBulb.Toggle(); 
    ... 
  } 
}`
33
wakqasahmed

L'intero punto di Dependency Injection (DI) è di mantenere il codice sorgente dell'applicazione clean e stable :

  • clean del codice di inizializzazione delle dipendenze
  • stable indipendentemente dalla dipendenza utilizzata

In pratica, ogni schema di progettazione separa le preoccupazioni per fare in modo che le modifiche future influiscano sui file minimi.

Il dominio specifico di DI è la delega della configurazione delle dipendenze e l'inizializzazione.

Esempio: DI con script Shell

Se occasionalmente lavori al di fuori di Java, ricorda come source è spesso usato in molti linguaggi di scripting (Shell, Tcl, ecc., O anche import in Python utilizzato male a questo scopo).

Considera semplice script dependent.sh:

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Lo script è dipendente: non verrà eseguito correttamente da solo (archive_files non è definito).

Definisci archive_files nello script di implementazione archive_files_Zip.sh (utilizzando Zip in questo caso):

#!/bin/sh
# Dependency
function archive_files {
    Zip files.Zip "[email protected]"
}

Invece di source-ing script di implementazione direttamente in quello dipendente, si usa un injector.sh "contenitore" che racchiude entrambi i "componenti":

#!/bin/sh 
# Injector
source ./archive_files_Zip.sh
source ./dependent.sh

Il archive_filesdependency è stato appena iniettato nello script dependent.

Si potrebbe avere una dipendenza iniettata che implementa archive_files usando tar o xz.

Esempio: rimozione DI

Se lo script dependent.sh utilizza direttamente le dipendenze, l'approccio sarebbe chiamato dependency lookup (che è opposto a dependency injection):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_Zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

Ora il problema è che il "componente" dipendente deve eseguire l'inizializzazione stessa.

Il codice sorgente del "componente" non è né clean stable perché ogni modifica nell'inizializzazione delle dipendenze richiede anche una nuova release per il file del codice sorgente "components".

Ultime parole

DI non è così ampiamente enfatizzato e divulgato come nei framework Java.

Ma è un approccio generico a dividere le preoccupazioni di:

  • application development ( single source code release lifecycle)
  • application deployment ( multiple target environment con cicli di vita indipendenti)

L'uso della configurazione solo con dependency lookup non aiuta in quanto il numero dei parametri di configurazione può cambiare per dipendenza (ad esempio nuovo tipo di autenticazione) e il numero di tipi di dipendenza supportati (ad esempio, nuovo tipo di database).

25
uvsmtid

Tutte le risposte di cui sopra sono buone, il mio obiettivo è quello di spiegare il concetto in modo semplice in modo che chiunque non abbia una conoscenza di programmazione possa anche capire il concetto

L'iniezione di dipendenza è uno degli schemi di progettazione che ci aiuta a creare sistemi complessi in modo più semplice.

Possiamo vedere un'ampia varietà di applicazione di questo modello nella nostra vita di tutti i giorni .. Alcuni esempi sono registratore a nastro, VCD, CD Drive, ecc.

 Reel-to-reel portable tape recorder, mid-20th century.

L'immagine sopra è un'immagine del registratore a nastro portatile Reel-to-reel, metà del 20 ° secolo. Fonte .

L'intenzione principale di un registratore è quella di registrare o riprodurre suoni.

Durante la progettazione di un sistema richiede una bobina per registrare o riprodurre suoni o musica. Ci sono due possibilità per progettare questo sistema

  1. possiamo posizionare la bobina all'interno della macchina
  2. possiamo fornire un gancio per la bobina dove può essere posizionato.

Se usiamo il primo, dobbiamo aprire la macchina per cambiare la bobina . Se optiamo per la seconda, che sta posizionando un gancio per bobina, stiamo ottenendo un ulteriore vantaggio di riprodurre qualsiasi musica cambiando la bobina . e anche riducendo la funzione solo per suonare qualsiasi cosa nella bobina.

Come l'iniezione saggia dipendenza è il processo di esternalizzazione delle dipendenze per concentrarsi solo sulla funzionalità specifica del componente in modo che i componenti indipendenti possono essere accoppiati insieme per formare un sistema complesso.

I principali benefici che abbiamo ottenuto utilizzando l'iniezione di dipendenza.

  • Elevata coesione e accoppiamento libero.
  • Esternalizzare la dipendenza e guardare solo alla responsabilità.
  • Fare cose come componenti e combinare per formare un sistema di grandi dimensioni con elevate capacità.
  • Aiuta a sviluppare componenti di alta qualità poiché sono sviluppati in modo indipendente e sono adeguatamente testati.
  • Aiuta a sostituire il componente con un altro se uno fallisce.

Ora un giorno questi concetti costituiscono la base di framework ben noti nel mondo della programmazione . Spring Angular etc sono i ben noti framework software costruiti sulla cima di questo concetto

L'iniezione di dipendenza è un modello utilizzato per creare istanze di oggetti su cui altri oggetti fanno affidamento senza sapere in fase di compilazione quale classe verrà utilizzata per fornire tale funzionalità o semplicemente il modo di iniettare le proprietà a un oggetto è chiamato iniezione di dipendenza.

Esempio per l'iniezione di dipendenza

In precedenza stiamo scrivendo un codice come questo

Public MyClass{
 DependentClass dependentObject
 /*
  At somewhere in our code we need to instantiate 
  the object with new operator  inorder to use it or perform some method.
  */ 
  dependentObject= new DependentClass();
  dependentObject.someMethod();
}

Con l'iniezione di dipendenza, l'iniettore di dipendenza decollerà per noi l'istanziazione 

Public MyClass{
 /* Dependency injector will instantiate object*/
 DependentClass dependentObject

 /*
  At somewhere in our code we perform some method. 
  The process of  instantiation will be handled by the dependency injector
 */ 

  dependentObject.someMethod();
}

Puoi anche leggere

Differenza tra inversione del controllo e iniezione delle dipendenze

18
Samuel J Mathew

Cos'è l'iniezione di dipendenza?

Iniezione di dipendenza (DI) significa disaccoppiare gli oggetti che sono dipendenti l'uno dall'altro. Dire che l'oggetto A dipende dall'oggetto B, quindi l'idea è di separare questi oggetti l'uno dall'altro. Non abbiamo bisogno di codificare l'oggetto con una nuova parola chiave piuttosto di condividere le dipendenze con gli oggetti in fase di runtime nonostante il tempo di compilazione ..__ Se parliamo di 

Come funziona l'iniezione di dipendenza in primavera:

Non è necessario codificare l'oggetto con una nuova parola chiave, piuttosto definire la dipendenza del bean nel file di configurazione. Il contenitore primavera sarà responsabile per il collegamento di tutti.

Inversion of Control (IOC)

Il CIO è un concetto generale e può essere espresso in molti modi diversi e l'iniezione di dipendenza è un esempio concreto di IOC.

Due tipi di iniezione delle dipendenze:

  1. Iniezione del costruttore
  2. Iniezione Setter

1. Iniezione di dipendenza basata sul costruttore:

Il DI basato sul costruttore viene eseguito quando il contenitore richiama un costruttore di classi con un numero di argomenti, ognuno dei quali rappresenta una dipendenza da un'altra classe.

public class Triangle {

private String type;

public String getType(){
    return type;
 }

public Triangle(String type){   //constructor injection
    this.type=type;
 }
}
<bean id=triangle" class ="com.test.dependencyInjection.Triangle">
        <constructor-arg value="20"/>
  </bean>

2. Iniezione di dipendenze basata su setter:

La DI basata su Setter viene eseguita dai metodi di richiamo di chiamata del contenitore sui bean dopo aver richiamato un costruttore senza argomenti o un metodo factory statico senza argomento per creare un'istanza del bean.

public class Triangle{

 private String type;

 public String getType(){
    return type;
  }
 public void setType(String type){          //setter injection
    this.type = type;
  }
 }

<!-- setter injection -->
 <bean id="triangle" class="com.test.dependencyInjection.Triangle">
        <property name="type" value="equivialteral"/>

NOTA: È una buona regola empirica utilizzare gli argomenti del costruttore per le dipendenze e i setter obbligatori per le dipendenze opzionali. Si noti che se si utilizza annotazione basata su annotazione @Required su un setter, è possibile utilizzare i setter come dipendenza richiesta.

17
Harleen

La migliore analogia che mi viene in mente è il chirurgo e il suo assistente (i) in una sala operatoria, dove il chirurgo è la persona principale e il suo assistente che fornisce i vari componenti chirurgici quando ne ha bisogno in modo che il chirurgo possa concentrarsi su quello cosa fa meglio (chirurgia). Senza l'assistente il chirurgo deve ottenere i componenti da solo ogni volta che ne ha bisogno.

DI in breve, è una tecnica per rimuovere una responsabilità aggiuntiva (onere) comune sui componenti per recuperare i componenti dipendenti, fornendoli ad essi.

DI ti avvicina al principio della Single Responsibility (SR), come il surgeon who can concentrate on surgery.

Quando utilizzare DI: mi consiglia di utilizzare DI in quasi tutti i progetti di produzione (piccoli/grandi), in particolare in ambienti aziendali in continuo cambiamento :)

Perché: perché desideri che il tuo codice sia facilmente verificabile, verificabile, ecc. In modo da poter testare rapidamente le tue modifiche e inviarlo al mercato. Inoltre, perché non lo faresti quando ci sono un sacco di fantastici strumenti/framework gratuiti per supportarti nel tuo viaggio verso una base di codice in cui hai più controllo.

15
Anwar Husain

Significa che gli oggetti dovrebbero avere quante dipendenze quante ne servono per fare il loro lavoro e le dipendenze dovrebbero essere poche. Inoltre, le dipendenze di un oggetto dovrebbero essere su interfacce e non su oggetti "concreti", quando possibile. (Un oggetto concreto è qualsiasi oggetto creato con la parola chiave new.) L'accoppiamento lento promuove una maggiore riusabilità, facilità di manutenzione e consente di fornire facilmente oggetti "finti" al posto di servizi costosi.

La "Dipendenza dell'iniezione" (DI) è anche conosciuta come "Inversione del controllo" (IoC), può essere usata come tecnica per incoraggiare questo accoppiamento lento.

Esistono due approcci principali per l'implementazione di DI:

  1. Iniezione del costruttore 
  2. Iniezione setter

Iniezione del costruttore

È la tecnica di passare le dipendenze degli oggetti al suo costruttore.

Si noti che il costruttore accetta un'interfaccia e non un oggetto concreto. Inoltre, si noti che viene generata un'eccezione se il parametro dell'ordine è nullo. Ciò sottolinea l'importanza di ricevere una dipendenza valida. Costruttore Iniezione è, a mio parere, il meccanismo preferito per dare a un oggetto le sue dipendenze. È chiaro allo sviluppatore durante il richiamo dell'oggetto le dipendenze che devono essere fornite all'oggetto "Persona" per la corretta esecuzione.

Iniezione Setter

Ma considera il seguente esempio ... Supponi di avere una classe con dieci metodi che non hanno dipendenze, ma stai aggiungendo un nuovo metodo che ha una dipendenza da IDAO. È possibile modificare la funzione di costruzione per utilizzare Iniezione costruttore, ma ciò potrebbe costringere a modificare tutte le chiamate del costruttore ovunque. In alternativa, puoi semplicemente aggiungere un nuovo costruttore che prende la dipendenza, ma come fa uno sviluppatore a sapere facilmente quando usare un costruttore sull'altro. Infine, se la dipendenza è molto costosa da creare, perché dovrebbe essere creata e passata al costruttore quando può essere usata solo raramente? "Setter Injection" è un'altra tecnica DI che può essere utilizzata in situazioni come questa.

Setter Injection non forza le dipendenze da passare al costruttore. Invece, le dipendenze sono impostate su proprietà pubbliche esposte dall'oggetto in stato di bisogno. Come implicito in precedenza, i principali motivatori per fare questo includono:

  1. Supportare l'integrazione delle dipendenze senza dover modificare il costruttore di una classe precedente.
  2. Permettere di creare risorse o servizi costosi il più tardi possibile e solo quando necessario.

Ecco l'esempio di come apparirebbe il codice sopra riportato:

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;
13

Esempio, abbiamo 2 classi Client e Service. Client utilizzerà Service

public class Service {
    public void doSomeThingInService() {
        // ...
    }
}

Senza iniezione di dipendenza

Way 1) 

public class Client {
    public void doSomeThingInClient() {
        Service service = new Service();
        service.doSomeThingInService();
    }
}

Via 2)

public class Client {
    Service service = new Service();
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Via 3) 

public class Client {
    Service service;
    public Client() {
        service = new Service();
    }
    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

1) 2) 3) Utilizzo di

Client client = new Client();
client.doSomeThingInService();

Vantaggi

  • Semplice

Svantaggi

  • Difficile per la prova della classe Client
  • Quando cambiamo il costruttore Service, abbiamo bisogno di cambiare il codice in tutti gli oggetti di creare posto Service

Utilizzare l'iniezione di dipendenza

Way 1) Iniezione del costruttore

public class Client {
    Service service;

    Client(Service service) {
        this.service = service;
    }

    // Example Client has 2 dependency 
    // Client(Service service, IDatabas database) {
    //    this.service = service;
    //    this.database = database;
    // }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Utilizzo 

Client client = new Client(new Service());
// Client client = new Client(new Service(), new SqliteDatabase());
client.doSomeThingInClient();

Way 2) Iniezione di setter

public class Client {
    Service service;

    public void setService(Service service) {
        this.service = service;
    }

    public void doSomeThingInClient() {
        service.doSomeThingInService();
    }
}

Utilizzo 

Client client = new Client();
client.setService(new Service());
client.doSomeThingInClient();

Way 3) Iniezione dell'interfaccia

Controlla https://en.wikipedia.org/wiki/Dependency_injection

=== 

Ora, questo codice è già seguito Dependency Injection ed è più semplice per la classe di prova Client.
Tuttavia, usiamo ancora new Service() molte volte e non è buono quando si cambia Service constructor. Per impedirlo, possiamo usare l'iniettore DI come
1) Manuale semplice Injector

public class Injector {
    public static Service provideService(){
        return new Service();
    }

    public static IDatabase provideDatatBase(){
        return new SqliteDatabase();
    }
    public static ObjectA provideObjectA(){
        return new ObjectA(provideService(...));
    }
}

Usando

Service service = Injector.provideService();

2) Usa libreria: per Android dagger2

Vantaggi

  • Fai test più facile
  • Quando si modifica Service, è necessario modificarlo solo nella classe Injector
  • Se usi use Constructor Injection, quando guardi il costruttore di Client, vedrai quante dipendenze della classe Client

Svantaggi 

  • Se usi use Constructor Injection, l'oggetto Service viene creato quando Client viene creato, a volte usiamo la funzione nella classe Client senza usare Service così creato Service è sprecato

Definizione di iniezione di dipendenza

https://en.wikipedia.org/wiki/Dependency_injection

Una dipendenza è un oggetto che può essere utilizzato (Service)
Un'iniezione è il passaggio di una dipendenza (Service) a un oggetto dipendente (Client) che lo userebbe

12
Linh

Penso che poiché tutti hanno scritto per DI, mi permetta di fare alcune domande ...

  1. Quando si ha una configurazione di DI in cui tutte le implementazioni effettive (non le interfacce) che verranno immesse in una classe (per i servizi di e.g ad un controller) perché non si tratta di una sorta di hard-coding? 
  2. Cosa succede se voglio cambiare l'oggetto in fase di runtime? Ad esempio, la mia configurazione dice già quando istanzio MyController, inject per FileLogger come ILogger. Ma potrei voler iniettare DatabaseLogger. 
  3. Ogni volta che voglio cambiare gli oggetti di cui il mio AClass ha bisogno, ho bisogno di esaminare due aspetti: la classe stessa e il file di configurazione. Come fa a rendere la vita più facile?
  4. Se Aproperty of AClass non viene iniettato, è più difficile deriderlo? 
  5. Tornando alla prima domanda. Se l'uso di new object () è negativo, come mai iniettiamo l'implementazione e non l'interfaccia? Penso che molti di voi stiano dicendo che stiamo in effetti iniettando l'interfaccia, ma la configurazione ti permette di specificare l'implementazione di quell'interfaccia .. non in fase di esecuzione .. è hardcoded durante la compilazione.

Questo si basa sulla risposta @Adam N pubblicato.

Perché PersonService non deve più preoccuparsi di GroupMembershipService? Hai appena menzionato GroupMembership ha più cose (oggetti/proprietà) da cui dipende. Se GMService fosse richiesto in PService, lo avresti come proprietà. Puoi deriderlo indipendentemente dal fatto che tu l'abbia iniettato o meno. L'unica volta che mi piacerebbe che fosse iniettata è se GMService avesse classi figlio più specifiche, che non avresti saputo fino al runtime. Quindi dovresti iniettare la sottoclasse. O se volessi usarlo come singleton o come prototipo. Per essere onesti, il file di configurazione ha tutto ciò che è hardcoded per quanto riguarda la sottoclasse di un tipo (interfaccia) che verrà iniettata durante la compilazione. 

MODIFICARE 

Un bel commento di Jose Maria Arranz su DI

DI aumenta la coesione eliminando qualsiasi necessità di determinare la direzione della dipendenza e scrivere qualsiasi codice di colla.

Falso. La direzione delle dipendenze è in formato XML o come annotazioni, le tue dipendenze sono scritte come codice XML e annotazioni. XML e annotazioni SONO il codice sorgente.

DI riduce l'accoppiamento rendendo tutti i componenti modulari (cioè sostituibili) e presentano interfacce ben definite l'una con l'altra.

Falso. Non è necessario un framework DI per creare un codice modulare basato su interfacce.

Informazioni sulla sostituzione: con un semplice archivio .properties e Class.forome è possibile definire quali classi possono cambiare. Se QUALSIASI classe del codice può essere modificata, Java non fa per te, usa un linguaggio di scripting. A proposito: le annotazioni non possono essere cambiate senza ricompilare.

A mio parere c'è un solo motivo per le strutture DI: riduzione della piastra della caldaia. Con un sistema factory ben fatto puoi fare lo stesso, più controllato e più prevedibile come il tuo framework DI preferito, i framework DI promettono la riduzione del codice (XML e le annotazioni sono anche codice sorgente). Il problema è che questa riduzione della piastra della caldaia è reale solo in casi molto semplici (un'istanza per classe e simili), a volte nel mondo reale la scelta dell'oggetto di servizio appropriato non è facile come mappare una classe a un oggetto singleton.

10
Chookoos

Iniezione delle dipendenze indica un modo (in realtà qualsiasi modo) per una parte del codice (ad esempio una classe) di avere accesso alle dipendenze (altre parti del codice, ad esempio altre classi, dipende da) in un modo modulare senza che siano codificati (in modo che possano cambiare o essere sostituiti liberamente o essere caricati in un altro momento, se necessario)

(e ps, sì è diventato un nome 25 $ troppo esagerato per un concetto piuttosto semplice), i miei .25 centesimi

8
Nikos M.

So che ci sono già molte risposte, ma ho trovato questo molto utile: http://tutorials.jenkov.com/dependency-injection/index.html

Nessuna dipendenza:

public class MyDao {

  protected DataSource dataSource =
    new DataSourceImpl("driver", "url", "user", "password");

  //data access methods...
  public Person readPerson(int primaryKey) {...}

}

Dipendenza:

public class MyDao {

  protected DataSource dataSource = null;

  public MyDao(String driver, String url, String user, String
 password){
    this.dataSource = new DataSourceImpl(driver, url, user, password);
  }

  //data access methods...
  public Person readPerson(int primaryKey)
  {...}

}

Si noti come l'istanza DataSourceImpl viene spostata in un costruttore. Il costruttore prende quattro parametri che sono i quattro valori necessari per DataSourceImpl. Sebbene la classe MyDao dipenda ancora da questi quattro valori, non soddisfa più queste dipendenze. Sono forniti da qualsiasi classe che crea un'istanza MyDao.

7
Ali Issa

Le risposte popolari non sono di aiuto, perché definiscono l'iniezione di dipendenza in un modo che non è utile. Siamo d'accordo che per "dipendenza" intendiamo alcuni altri oggetti preesistenti di cui il nostro oggetto X ha bisogno. Ma non diciamo che stiamo facendo "iniezione di dipendenza" quando diciamo

$foo = Foo->new($bar);

Chiamiamo semplicemente quei parametri che passano nel costruttore. Lo stiamo facendo regolarmente da quando sono stati inventati i costruttori.

"Iniezione di dipendenza" è considerato un tipo di "inversione del controllo", il che significa che una parte della logica viene eliminata dal chiamante. Questo non è il caso quando il chiamante passa i parametri, quindi se questo fosse DI, DI non implicherebbe inversione di controllo.

DI significa che esiste un livello intermedio tra il chiamante e il costruttore che gestisce le dipendenze. Un Makefile è un semplice esempio di iniezione di dipendenza. Il "chiamante" è la persona che scrive "make bar" sulla riga di comando e il "costruttore" è il compilatore. Il Makefile specifica che la barra dipende da foo, e fa a

gcc -c foo.cpp; gcc -c bar.cpp

prima di fare un

gcc foo.o bar.o -o bar

La persona che scrive "make bar" non ha bisogno di sapere che la barra dipende da foo. La dipendenza è stata iniettata tra "make bar" e gcc.

Lo scopo principale del livello intermedio non è solo quello di passare le dipendenze al costruttore, ma di elencare tutte le dipendenze in solo un posto , e di nasconderle dal coder (non per farle fornire al codificatore) .

Di solito il livello intermedio fornisce le fabbriche per gli oggetti costruiti, che devono fornire un ruolo che ogni tipo di oggetto richiesto deve soddisfare. Questo perché avendo un livello intermedio che nasconde i dettagli della costruzione, hai già subito la penalità per l'astrazione imposta dalle fabbriche, quindi potresti anche usare le fabbriche.

7
Phil Goetz

L'iniezione di dipendenza è una possibile soluzione a ciò che in genere potrebbe essere definito il requisito "Obfuscation dipendenza". Dipendenza L'offuscamento è un metodo per togliere la natura "ovvia" dal processo di fornire una dipendenza a una classe che lo richiede e quindi offuscare, in qualche modo, la fornitura di detta dipendenza a detta classe. Ciò non è necessariamente una cattiva cosa. Infatti, offuscando il modo con cui viene fornita una dipendenza a una classe, qualcosa al di fuori della classe è responsabile della creazione della dipendenza, il che significa che, in vari scenari, una diversa implementazione della dipendenza può essere fornita alla classe senza apportare alcuna modifica alla classe. Questo è ottimo per passare dalla modalità di produzione a quella di test (ad esempio, usando una dipendenza dal servizio "fittizio").

Sfortunatamente la parte cattiva è che alcune persone hanno pensato che tu abbia bisogno di un framework specializzato per fare l'offuscamento delle dipendenze e che tu sia in qualche modo un programmatore "minore" se scegli di non usare un particolare framework per farlo. Un altro mito estremamente inquietante, creduto da molti, è che l'iniezione di dipendenza è l'unico modo per ottenere l'offuscamento della dipendenza. Questo è dimostrabile, storicamente e ovviamente sbagliato al 100%, ma avrete difficoltà a convincere alcune persone che ci sono alternative all'iniezione di dipendenza per i vostri requisiti di offuscamento delle dipendenze.

I programmatori hanno compreso i requisiti di offuscamento delle dipendenze per anni e molte soluzioni alternative si sono evolute sia prima che dopo l'ideazione dell'iniezione di dipendenza. Esistono modelli di fabbrica ma ci sono anche molte opzioni che usano ThreadLocal dove non è necessaria alcuna iniezione su una particolare istanza - la dipendenza viene effettivamente iniettata nel thread che ha il vantaggio di rendere l'oggetto disponibile (tramite i metodi getter statici di convenienza) a qualsiasi classe che lo richiede senza dover aggiungere annotazioni alle classi che lo richiedono e impostare una "colla" XML complicata per farlo accadere. Quando le tue dipendenze sono richieste per la persistenza (JPA/JDO o qualsiasi altra cosa) ti consente di ottenere una "persistenza ininterrotta" molto più semplice e con classi di modelli di business e modello di dominio costituiti esclusivamente da POJOs (cioè nessun framework specifico/bloccato nelle annotazioni).

6
Volksman

From the Book, ' Sviluppatore Java ben sviluppato: tecniche vitali di Java 7 e programmazione poliglotta

DI è una forma particolare di IoC, per cui il processo di ricerca delle dipendenze è al di fuori del controllo diretto del codice attualmente in esecuzione.

5
TastyCode

Dipendenza dell'iniezione (DI) è uno dei modelli di progettazione, che utilizza la caratteristica di base di OOP - la relazione in un oggetto con un altro oggetto. Mentre l'ereditarietà eredita un oggetto per rendere più complesso e specifico un altro oggetto, relazione o associazione crea semplicemente un puntatore a un altro oggetto da un oggetto usando l'attributo. La potenza di DI è in combinazione con altre funzionalità di OOP come lo sono le interfacce e il codice nascosto . Supponiamo di avere un cliente (abbonato) nella libreria, che può prendere in prestito solo un libro per semplicità.

Interfaccia del libro:

package com.deepam.hidden;

public interface BookInterface {

public BookInterface setHeight(int height);
public BookInterface setPages(int pages);   
public int getHeight();
public int getPages();  

public String toString();
}

Successivamente possiamo avere molti tipi di libri; uno di tipo è finzione:

package com.deepam.hidden;

public class FictionBook implements BookInterface {
int height = 0; // height in cm
int pages = 0; // number of pages

/** constructor */
public FictionBook() {
    // TODO Auto-generated constructor stub
}

@Override
public FictionBook setHeight(int height) {
  this.height = height;
  return this;
}

@Override
public FictionBook setPages(int pages) {
  this.pages = pages;
  return this;      
}

@Override
public int getHeight() {
    // TODO Auto-generated method stub
    return height;
}

@Override
public int getPages() {
    // TODO Auto-generated method stub
    return pages;
}

@Override
public String toString(){
    return ("height: " + height + ", " + "pages: " + pages);
}
}

Ora l'abbonato può avere un'associazione con il libro:

package com.deepam.hidden;

import Java.lang.reflect.Constructor;
import Java.lang.reflect.InvocationTargetException;

public class Subscriber {
BookInterface book;

/** constructor*/
public Subscriber() {
    // TODO Auto-generated constructor stub
}

// injection I
public void setBook(BookInterface book) {
    this.book = book;
}

// injection II
public BookInterface setBook(String bookName) {
    try {
        Class<?> cl = Class.forName(bookName);
        Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructor
        BookInterface book = (BookInterface) constructor.newInstance();
        //book = (BookInterface) Class.forName(bookName).newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return book;
}

public BookInterface getBook() {
  return book;
}

public static void main(String[] args) {

}

}

Tutte le tre classi possono essere nascoste per la sua implementazione. Ora possiamo usare questo codice per DI:

package com.deepam.implement;

import com.deepam.hidden.Subscriber;
import com.deepam.hidden.FictionBook;

public class CallHiddenImplBook {

public CallHiddenImplBook() {
    // TODO Auto-generated constructor stub
}

public void doIt() {
    Subscriber ab = new Subscriber();

    // injection I
    FictionBook bookI = new FictionBook();
    bookI.setHeight(30); // cm
    bookI.setPages(250);
    ab.setBook(bookI); // inject
    System.out.println("injection I " + ab.getBook().toString());

    // injection II
    FictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and set
    System.out.println("injection II " + ab.getBook().toString());      
}

public static void main(String[] args) {
    CallHiddenImplBook kh = new CallHiddenImplBook();
    kh.doIt();
}
}

Esistono molti modi diversi per utilizzare l'iniezione di dipendenza. È possibile combinarlo con Singleton, ecc., Ma in realtà è solo un'associazione realizzata creando un attributo di tipo di oggetto all'interno di un altro oggetto. L'utilità è solo e solo nella funzionalità, quel codice, che dovremmo scrivere ancora e ancora è sempre preparato e fatto per noi avanti. Questo è il motivo per cui DI è così strettamente legato a Inversion of Control (IoC) che significa che il nostro programma passa a controllare un altro modulo in esecuzione, che fa le iniezioni di bean al nostro codice. (Ogni oggetto, che può essere iniettato, può essere firmato o considerato come un bean.) Ad esempio, in primavera viene fatto creando e inizializzando ApplicationContext container, che funziona per noi. Semplicemente nel nostro codice creiamo il Contesto e invochiamo l'inizializzazione dei bean. In quel momento l'iniezione è stata eseguita automaticamente.

4
hariprasad

da Libro Apress.Spring.Persistence.with.Hibernate.Oct.2010

Lo scopo dell'iniezione di dipendenza è disaccoppiare il lavoro di risolvere i componenti software esterni dal business delle applicazioni logica. Senza l'iniezione di dipendenza, i dettagli di come un componente accesso ai servizi richiesti può essere confuso con il componente codice. Questo non solo aumenta il potenziale di errori, aggiunge il codice gonfiare e ingigantire le complessità di manutenzione; accoppia componenti insieme più da vicino, rendendo difficile modificare le dipendenze quando refactoring o test.

In parole semplici, l'iniezione di dipendenza (DI) è il modo per rimuovere le dipendenze o l'accoppiamento stretto tra oggetti diversi. L'iniezione di dipendenza conferisce un comportamento coerente a ciascun oggetto. 

DI è l'implementazione di IOC principal di Spring che dice "Non chiamarci, ti chiameremo". Usando il programmatore di dipendenza dipendenza non è necessario creare oggetti utilizzando la nuova parola chiave. 

Gli oggetti vengono caricati una volta nel contenitore Spring e quindi li riutilizziamo ogni volta che ne abbiamo bisogno recuperando quegli oggetti dal contenitore Spring usando il metodo getBean (String beanName).

3
Waqas Ahmed

Iniezione di dipendenza (DI) fa parte della pratica del principio di inversione di dipendenza (DIP), che viene anche chiamata Inversion of Control (IoC). Fondamentalmente devi fare DIP perché vuoi rendere il tuo codice più modulare e testabile, invece di un solo sistema monolitico. Quindi inizi a identificare parti del codice che possono essere separate dalla classe e astratte. Ora l'implementazione dell'astrazione deve essere iniettata dall'esterno della classe. Normalmente questo può essere fatto tramite costruttore. Quindi si crea un costruttore che accetta l'astrazione come parametro e questo è chiamato dependency injection (tramite costruttore). Per ulteriori spiegazioni sui contenitori DIP, DI e IoC puoi leggere Qui

3

L'iniezione di dipendenza è il cuore del concetto correlato a Spring Framework. Anche se creare la struttura di qualsiasi molla di progetto può svolgere un ruolo vitale, qui l'iniezione di dipendenza entra in azione.

In realtà, supponiamo che in Java siano state create due classi diverse come classe A e classe B, e qualunque sia la funzione disponibile in classe B che si desidera utilizzare in classe A, Quindi in quel momento si può usare l'iniezione di dipendenza . Dove è possibile oggetto di una classe in un'altra classe, allo stesso modo è possibile iniettare un'intera classe in un'altra classe per renderla accessibile . In questo modo la dipendenza può essere superata.

INIEZIONE DELLA DIPENDENZA IS SEMPLICEMENTE INCOLLANDO DUE CLASSI E AT ALLO STESSO TEMPO MANTENENDO SEPARATI.

3
mohit sarsar

Proporrei una definizione leggermente diversa, breve e precisa di cosa sia l'iniezione di dipendenza, concentrandomi sull'obiettivo primario, non sui mezzi tecnici (seguendo da qui ):

Dipendenza L'iniezione è il processo di creazione statico, stateless grafico degli oggetti di servizio, in cui ogni servizio è parametrizzato dal suo dipendenze.

Gli oggetti che creiamo nelle nostre applicazioni (indipendentemente dal fatto che usiamo Java, C # o altri linguaggi orientati agli oggetti) rientrano in genere in due categorie: "oggetti di servizio" stateless e statici (moduli) e statici, dinamici e locali "Oggetti dati".

Il grafico del modulo, il grafico degli oggetti di servizio, viene in genere creato all'avvio dell'applicazione. Questo può essere fatto usando un contenitore, come Spring, ma può anche essere fatto manualmente, passando i parametri ai costruttori di oggetti. Entrambi i modi hanno i loro pro e contro, ma non è assolutamente necessario un framework per utilizzare DI nella tua applicazione.

Un requisito è che i servizi devono essere parametrizzati dalle loro dipendenze. Ciò significa che dipende esattamente dalla lingua e dall'approccio adottati in un determinato sistema. Di solito, questo assume la forma di parametri del costruttore, ma l'uso dei setter è anche un'opzione. Ciò significa anche che le dipendenze di un servizio sono nascoste (quando si richiama un metodo di servizio) dagli utenti del servizio.

Quando usare? Direi che ogni volta che l'applicazione è abbastanza grande da incapsulare la logica in moduli separati, con un grafico di dipendenza tra i moduli si ottiene un guadagno in leggibilità ed esplorabilità del codice.

2
adamw

Dipendenza L'iniezione è la pratica per rendere indipendente la componente disaccoppiata da alcune delle loro dipendenze, seguendo la linea guida SOLID che dice

Principio di inversione delle dipendenze: si dovrebbe "dipendere dalle astrazioni, Non dalle concrezioni.

La migliore implementazione di Dependency Injection è il pattern di progettazione Composition Root, in quanto consente di disaccoppiare i componenti dal contenitore di iniezione delle dipendenze.

Raccomando questo fantastico articolo su Composition Root http://blog.ploeh.dk/2011/07/28/CompositionRoot/ Scritto da Mark Seemann

ecco i punti essenziali di questo articolo:

Una radice di composizione è una posizione (preferibilmente) unica in un'applicazione dove i moduli sono composti insieme.

...

Solo le applicazioni dovrebbero avere Composte Roots. Librerie e i quadri non dovrebbero.

...

Un contenitore DI dovrebbe essere referenziato solo dalla radice di composizione . Tutti gli altri moduli non dovrebbero avere alcun riferimento al contenitore.

La documentazione di Di-Ninja, un framework per l'iniezione delle dipendenze, è un ottimo esempio per dimostrare come funziona i principi di Composition Root e Dependency Injection . https://github.com/di-ninja/di-ninja Come so, è l'unico DiC in javascript che implementa il pattern di progettazione Composition-Root.

1
Jo Takion

Da Christoffer Noring, il libro di Pablo Deeleman "Learning Angular - Second Edition":

"Man mano che le nostre applicazioni crescono e si evolvono, ciascuna delle nostre entità di codice richiederà internamente istanze di altri oggetti, che sono meglio conosciute come dipendenze nel mondo dell'ingegneria del software.L'azione di passare tali dipendenze al client dipendente è nota come iniezione, e implica anche la partecipazione di un'altra entità di codice, denominata l'iniettore, che si prenderà la responsabilità di creare un'istanza e di eseguire il bootstrap delle dipendenze richieste in modo che siano pronte per l'uso dal momento stesso in cui vengono iniettate con successo nel client. il client non sa nulla su come istanziare le proprie dipendenze ed è solo a conoscenza dell'interfaccia che implementa per poterle utilizzare. "

1
H S Progr

Iniezione delle dipendenze è un tipo di implementazione del principio " Inversion of Control " su cui si basa la costruzione di Framework.

I framework come indicato in "Design Pattern" di GoF sono classi che implementano la logica del flusso di controllo principale sollevando lo sviluppatore a farlo, in questo modo i Framework realizzano l'inversione del principio di controllo.

Un modo per implementare come tecnica, e non come gerarchia di classi, questo principio di IoC è solo Iniezione di dipendenza.

DIconsiste principalmente nel delegare la mappatura delle istanze delle classi e il riferimento al tipo di tali istanze, ad una "entità" esterna: un oggetto, una classe statica, un componente, una struttura, ecc ... 

Le istanze delle classi sono "dependencies", l'associazione esterna del componente chiamante con l'istanza della classe attraverso il riferimento è "injection".

Ovviamente è possibile implementare questa tecnica in molti modi come si desidera dal punto di vista OOP, vedere ad esempio constructor injection, setter injection, interface injection.

Delegare una terza parte per svolgere l'attività di abbinare un riferimento a un oggetto è molto utile quando si desidera separare completamente un componente che richiede alcuni servizi dalla stessa implementazione di servizi. 

In questo modo, quando si progettano i componenti, è possibile concentrarsi esclusivamente sulla loro architettura e sulla loro logica specifica, affidandosi alle interfacce per collaborare con altri oggetti senza preoccuparsi di alcun tipo di modifiche all'implementazione degli oggetti/servizi utilizzati, anche se lo stesso oggetto si sta utilizzando sarà totalmente sostituito (ovviamente rispettando l'interfaccia).

1
Ciro Corvino

Qualsiasi applicazione non banale è composta da due o più classi che collaborano tra loro per eseguire alcune logiche di business. Tradizionalmente, ogni oggetto è responsabile per ottenere i propri riferimenti agli oggetti con cui collabora (le sue dipendenze). Quando si applica DI, agli oggetti vengono assegnate le loro dipendenze al momento della creazione da parte di qualche entità esterna che coordina ciascun oggetto nel sistema. In altre parole, le dipendenze sono iniettate in oggetti.

Per ulteriori dettagli, consultare inserire la descrizione del collegamento qui

0
Hisham Javed

DI è il modo in cui gli oggetti reali interagiscono l'uno con l'altro senza che un oggetto sia responsabile dell'esistenza di un altro oggetto. Gli oggetti dovrebbero essere trattati in uguaglianza. Sono tutti oggetti. Nessuno dovrebbe comportarsi come un creatore. Questo è il modo in cui rendi giustizia ai tuoi oggetti.

Semplice esempio

se hai bisogno di un medico, vai semplicemente a cercarne uno (esistente). Non penserai di creare un medico da zero per aiutarti. Esiste già e può servire voi o altri oggetti. Ha il diritto di esistere indipendentemente dal fatto che tu (un singolo oggetto) abbia o meno bisogno di lui perché il suo scopo è quello di servire uno o più oggetti. Chi ha deciso che la sua esistenza è Dio onnipotente, non selezione naturale. Pertanto, un vantaggio di DI consiste nell'evitare di creare inutili oggetti ridondanti che vivono senza uno scopo durante la vita del tuo universo (ad esempio l'applicazione).

0
Shadi Namrouti