Domanda

Sono già state pubblicate diverse domande con domande specifiche su iniezione di dipendenza , come ad esempio quando usalo e quali framework ci sono per esso. Tuttavia,

Che cos'è l'iniezione di dipendenza e quando / perché dovrebbe o non dovrebbe essere utilizzata?

È stato utile?

Soluzione

Iniezione di dipendenza sta passando la dipendenza ad altri oggetti o quadro (iniettore di dipendenza).

L'iniezione delle dipendenze semplifica i test. L'iniezione può essere effettuata tramite costruttore .

SomeClass () ha il suo costruttore come segue:

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

problema : Se myObject comporta attività complesse come l'accesso al disco o l'accesso alla rete, è difficile eseguire test unitari su SomeClass () . I programmatori devono deridere myObject e potrebbero intercettare la chiamata di fabbrica.

Soluzione alternativa :

  • Passando myObject come argomento al costruttore
public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

myObject può essere passato direttamente per semplificare i test.

  • Un'alternativa comune è la definizione di un costruttore che non fa nulla . L'iniezione di dipendenza può essere effettuata tramite setter. (h / t @MikeVella).
  • Martin Fowler documenta una terza alternativa (h / t @MarcDix), dove < strong> classi implementa esplicitamente un'interfaccia per le dipendenze che i programmatori desiderano iniettare.

È più difficile isolare i componenti nel test unitario senza iniezione di dipendenza.

Nel 2013, quando ho scritto questa risposta, questo era un tema importante sul Blog sui test di Google . Rimane il più grande vantaggio per me, poiché i programmatori non hanno sempre bisogno della flessibilità aggiuntiva nella loro progettazione di runtime (ad esempio, per localizzatore di servizio o schemi simili). I programmatori spesso devono isolare le classi durante i test.

Altri suggerimenti

La migliore definizione che ho trovato finora è uno di James Shore :

  

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

Esiste un articolo di Martin Fowler che può rivelarsi utile anche.

L'iniezione di dipendenza fornisce sostanzialmente gli oggetti di cui un oggetto ha bisogno (le sue dipendenze) invece di farli costruire da soli. È una tecnica molto utile per i test, poiché consente di deridere o eliminare le dipendenze.

Le dipendenze possono essere iniettate negli oggetti in molti modi (come l'iniezione del costruttore o l'iniezione del setter). Si può anche usare framework di iniezione di dipendenza specializzati (ad es. Spring) per farlo, ma certamente non sono richiesti. Non sono necessari quei framework per l'iniezione di dipendenza. L'istanza e il passaggio esplicito di oggetti (dipendenze) è un'iniezione altrettanto valida dell'iniezione per quadro.

Ho trovato questo divertente esempio in termini di accoppiamento libero :

Qualsiasi applicazione è composta da molti oggetti che collaborano tra loro per eseguire alcune cose utili. Tradizionalmente ogni oggetto è responsabile dell'ottenimento dei 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 .

Un Car dipende da ruote, motore, carburante, batteria, ecc. per funzionare. Tradizionalmente definiamo il marchio di tali oggetti dipendenti insieme alla definizione dell'oggetto Car .

Senza dipendenza dall'iniezione (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.

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

Quindi cosa ci fa Iniezione di dipendenza per ...?

Quando si usa l'iniezione delle dipendenze, agli oggetti vengono date le loro dipendenze in fase di esecuzione anziché in fase di compilazione (tempo di produzione delle automobili) . In modo che ora possiamo cambiare la Wheel ogni volta che vogliamo. Qui, dipendenza ( wheel ) può essere iniettato in Car in fase di esecuzione.

Dopo aver utilizzato l'iniezione delle dipendenze:

Qui, stiamo iniettando le dipendenze (ruota e batteria) in fase di esecuzione. Da qui il termine: Iniezione delle dipendenze.

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 di dipendenza

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

Ad esempio, considera questi casi:

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 fare il suo lavoro. Senza Iniezione delle dipendenze, il modo tradizionale di farlo sarebbe quello di creare un'istanza di un nuovo GroupMembershipService nel costruttore di PersonService e utilizzare quell'attributo di istanza in entrambe le funzioni. Tuttavia, se il costruttore di GroupMembershipService ha più cose che richiede, o peggio ancora, ci sono alcune inizializzazioni "setter". che devono essere chiamati sul GroupMembershipService , il codice cresce piuttosto rapidamente e il PersonService ora dipende non solo dal GroupMembershipService ma anche da tutto il resto da cui GroupMembershipService dipende. Inoltre, il collegamento a GroupMembershipService è codificato nel PersonService , il che significa che non puoi " manichino up " un GroupMembershipService a scopo di test o per utilizzare un modello di strategia in diverse parti dell'applicazione.

Con Dependency Injection, invece di creare un'istanza del GroupMembershipService all'interno del tuo PersonService , lo passeresti al costruttore PersonService , oppure altrimenti aggiungi una proprietà (getter e setter) per impostarne un'istanza locale. Ciò significa che il tuo PersonService non deve più preoccuparsi di come creare un GroupMembershipService , accetta solo quelli forniti e lavora con loro. Ciò significa anche che tutto ciò che è una sottoclasse di GroupMembershipService o che implementa l'interfaccia GroupMembershipService può essere " iniettato " nel PersonService e il PersonService non ha bisogno di conoscere la modifica.

La risposta accettata è buona, ma vorrei aggiungere che DI è molto simile al classico evitare le costanti codificate nel codice.

Quando usi una costante come il nome di un database, la sposteresti rapidamente dall'interno del codice in un file di configurazione e passeresti una variabile contenente quel valore nel punto in cui è necessario. Il motivo per farlo è che queste costanti di solito cambiano più frequentemente rispetto al resto del codice. Ad esempio, se si desidera testare il codice in un database di prova.

DI è analogo a questo nel mondo della programmazione orientata agli oggetti. I valori lì anziché i letterali costanti sono oggetti interi - ma il motivo per spostare il codice creandoli dal codice di classe è simile - gli oggetti cambiano più frequentemente del codice che li utilizza. Un caso importante in cui è necessario un simile cambiamento sono i test.

Proviamo un semplice esempio con le classi Auto e Motore , 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 associato 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 utilizzare un nuovo tipo di motore.

In altre parole, con questo approccio è che la nostra classe Car di alto livello dipende dalla classe GasEngine di livello inferiore che viola il principio di inversione di dipendenza (DIP) da SOLID. DIP suggerisce che dovremmo dipendere da astrazioni, non da classi 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 Car e darle una vera e propria classe di motori in cemento come GasEngine o ElectricityEngine. È qui che entra in gioco Iniezione delle dipendenze .

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

Qui sostanzialmente iniettiamo (passiamo) la nostra dipendenza (istanza Engine) al costruttore di auto. Quindi ora le nostre classi hanno un accoppiamento libero tra gli oggetti e le loro dipendenze e possiamo facilmente aggiungere nuovi tipi di motori senza cambiare la classe Car.

Il principale vantaggio della Iniezione delle dipendenze è che le classi sono accoppiate più liberamente, perché non hanno dipendenze codificate. Ciò segue il principio di inversione di dipendenza, che è stato menzionato sopra. Invece di fare riferimento a implementazioni specifiche, le classi richiedono astrazioni (in genere interfacce ) che vengono fornite loro quando viene costruita la classe.

  

Quindi alla fine Iniezione di dipendenza è solo una tecnica per   ottenere un accoppiamento libero tra gli oggetti e le loro dipendenze.   Piuttosto che istanziare direttamente le dipendenze di cui la classe ha bisogno   per eseguire le sue azioni, vengono fornite dipendenze alla classe   (il più delle volte) tramite l'iniezione del costruttore.

Inoltre, quando abbiamo molte dipendenze, è buona norma usare i contenitori 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 risolvano quelle dipendenze per noi quando costruisce il nostro oggetto. Ad esempio, potremmo specificare nella mappatura per il contenitore IoC che la dipendenza IEngine dovrebbe essere mappata alla classe GasEngine e quando chiediamo al contenitore IoC un'istanza del nostro Classe Auto , costruirà automaticamente la nostra classe Auto con una dipendenza GasEngine passata.

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

  

L'iniezione di dipendenza è un modello per consentire l'iniezione dell'applicazione   oggetti al volo per le classi che ne hanno bisogno, senza forzare quelli   classi responsabili di tali oggetti. Permette al tuo codice di essere   accoppiati più liberamente, e Entity Framework Core si collega a questo stesso   sistema di servizi.

Immaginiamo che tu voglia andare a pescare:

  • Senza iniezione di dipendenza, devi prenderti cura di tutto da solo. Devi trovare una barca, comprare una canna da pesca, cercare esche, ecc. È possibile, ovviamente, ma ti dà molte responsabilità. In termini di software, significa che devi eseguire una ricerca per tutte queste cose.

  • Con l'iniezione delle dipendenze, qualcun altro si occupa di tutta la preparazione e mette a disposizione le attrezzature necessarie. Riceverai ("ti verrà iniettato") la barca, la canna da pesca e l'esca - tutte pronte per l'uso.

Questa è la spiegazione più semplice su Iniezione di dipendenza e Contenitore di iniezione delle dipendenze che abbia mai visto:

Senza iniezione di dipendenza

  • L'applicazione richiede Foo (ad esempio un controller), quindi:
  • L'applicazione crea Foo
  • L'applicazione chiama Foo
    • Foo ha bisogno di una barra (ad es. un servizio), quindi:
    • Foo crea Bar
    • Foo chiama Bar
      • Bar ha bisogno di Bim (un servizio, un repository, & # 8230;), quindi:
      • Bar crea Bim
      • Bar fa qualcosa

Con Iniezione delle dipendenze

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

Utilizzo di un contenitore di iniezione di dipendenza

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

Iniezione di dipendenza e Contenitori di iniezione di dipendenza sono cose diverse:

  • Iniezione delle dipendenze è un metodo per scrivere codice migliore
  • un contenitore DI è uno strumento che aiuta a iniettare dipendenze

Non è necessario un contenitore per eseguire l'iniezione delle dipendenze. Tuttavia, un contenitore può aiutarti.

Non " iniezione di dipendenza " intendi semplicemente usare costruttori parametrici e setter pubblici?

L'articolo di James Shore mostra i seguenti esempi di 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(); 
    ... 
  } 
}

What is Dependency Injection (DI)?

As others have said, Dependency Injection(DI) removes the responsibility of direct creation, and management of the lifespan, of other object instances upon which our class of interest (consumer class) is dependent (in the UML sense). These instances are instead passed to our consumer class, typically as constructor parameters or via property setters (the management of the dependency object instancing and passing to the consumer class is usually performed by an Inversion of Control (IoC) container, but that's another topic).

DI, DIP and SOLID

Specifically, in the paradigm of Robert C Martin's SOLID principles of Object Oriented Design, DI is one of the possible implementations of the Dependency Inversion Principle (DIP). The DIP is the D of the SOLID mantra - other DIP implementations include the Service Locator, and Plugin patterns.

The objective of the DIP is to decouple tight, concrete dependencies between classes, and instead, to loosen the coupling by means of an abstraction, which can be achieved via an interface, abstract class or pure virtual class, depending on the language and approach used.

Without the DIP, our code (I've called this 'consuming class') is directly coupled to a concrete dependency and is also often burdened with the responsibility of knowing how to obtain, and manage, an instance of this dependency, i.e. conceptually:

"I need to create/use a Foo and invoke method `GetBar()`"

Whereas after application of the DIP, the requirement is loosened, and the concern of obtaining and managing the lifespan of the Foo dependency has been removed:

"I need to invoke something which offers `GetBar()`"

Why use DIP (and DI)?

Decoupling dependencies between classes in this way allows for easy substitution of these dependency classes with other implementations which also fulfil the prerequisites of the abstraction (e.g. the dependency can be switched with another implementation of the same interface). Moreover, as others have mentioned, possibly the most common reason to decouple classes via the DIP is to allow a consuming class to be tested in isolation, as these same dependencies can now be stubbed and/or mocked.

One consequence of DI is that the lifespan management of dependency object instances is no longer controlled by a consuming class, as the dependency object is now passed into the consuming class (via constructor or setter injection).

This can be viewed in different ways:

  • If lifespan control of dependencies by the consuming class needs to be retained, control can be re-established by injecting an (abstract) factory for creating the dependency class instances, into the consumer class. The consumer will be able to obtain instances via a Create on the factory as needed, and dispose of these instances once complete.
  • Or, lifespan control of dependency instances can be relinquished to an IoC container (more about this below).

When to use DI?

  • Where there likely will be a need to substitute a dependency for an equivalent implementation,
  • Any time where you will need to unit test the methods of a class in isolation of its dependencies,
  • Where uncertainty of the lifespan of a dependency may warrant experimentation (e.g. Hey, MyDepClass is thread safe - what if we make it a singleton and inject the same instance into all consumers?)

Example

Here's a simple C# implementation. Given the below Consuming class:

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

Although seemingly innocuous, it has two static dependencies on two other classes, System.DateTime and System.Console, which not only limit the logging output options (logging to console will be worthless if no one is watching), but worse, it is difficult to automatically test given the dependency on a non-deterministic system clock.

We can however apply DIP to this class, by abstracting out the the concern of timestamping as a dependency, and coupling MyLogger only to a simple interface:

public interface IClock
{
    DateTime Now { get; }
}

We can also loosen the dependency on Console to an abstraction, such as a TextWriter. Dependency Injection is typically implemented as either constructor injection (passing an abstraction to a dependency as a parameter to the constructor of a consuming class) or Setter Injection (passing the dependency via a setXyz() setter or a .Net Property with {set;} defined). Constructor Injection is preferred, as this guarantees the class will be in a correct state after construction, and allows the internal dependency fields to be marked as readonly (C#) or final (Java). So using constructor injection on the above example, this leaves us with:

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(A concrete Clock needs to be provided, which of course could revert to DateTime.Now, and the two dependencies need to be provided by an IoC container via constructor injection)

An automated Unit Test can be built, which definitively proves that our logger is working correctly, as we now have control over the dependencies - the time, and we can spy on the written output:

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

Next Steps

Dependency injection is invariably associated with an Inversion of Control container(IoC), to inject (provide) the concrete dependency instances, and to manage lifespan instances. During the configuration / bootstrapping process, IoC containers allow the following to be defined:

  • mapping between each abstraction and the configured concrete implementation (e.g. "any time a consumer requests an IBar, return a ConcreteBar instance")
  • policies can be set up for the lifespan management of each dependency, e.g. to create a new object for each consumer instance, to share a singleton dependency instance across all consumers, to share the same dependency instance only across the same thread, etc.
  • In .Net, IoC containers are aware of protocols such as IDisposable and will take on the responsibility of Disposing dependencies in line with the configured lifespan management.

Typically, once IoC containers have been configured / bootstrapped, they operate seamlessly in the background allowing the coder to focus on the code at hand rather than worrying about dependencies.

The key to DI-friendly code is to avoid static coupling of classes, and not to use new() for the creation of Dependencies

As per above example, decoupling of dependencies does require some design effort, and for the developer, there is a paradigm shift needed to break the habit of newing dependencies directly, and instead trusting the container to manage dependencies.

But the benefits are many, especially in the ability to thoroughly test your class of interest.

Note : The creation / mapping / projection (via new ..()) of POCO / POJO / Serialization DTOs / Entity Graphs / Anonymous JSON projections et al - i.e. "Data only" classes or records - used or returned from methods are not regarded as Dependencies (in the UML sense) and not subject to DI. Using new to project these is just fine.

To make Dependency Injection concept simple to understand. Let's take an example of switch button to toggle(on/off) a bulb.

Without Dependency Injection

Switch needs to know beforehand which bulb I am connected to (hard-coded dependency). So,

Switch -> PermanentBulb //switch is directly connected to permanent bulb, testing not possible easily

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

With Dependency Injection

Switch only knows I need to turn on/off whichever Bulb is passed to me. So,

Switch -> Bulb1 OR Bulb2 OR NightBulb (injected dependency)

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

Modifying James Example for Switch and Bulb:

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(); 
    ... 
  } 
}`

The whole point of Dependency Injection (DI) is to keep application source code clean and stable:

  • clean of dependency initialization code
  • stable regardless of dependency used

Practically, every design pattern separates concerns to make future changes affect minimum files.

The specific domain of DI is delegation of dependency configuration and initialization.

Example: DI with shell script

If you occasionally work outside of Java, recall how source is often used in many scripting languages (Shell, Tcl, etc., or even import in Python misused for this purpose).

Consider simple dependent.sh script:

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

The script is dependent: it won't execute successfully on its own (archive_files is not defined).

You define archive_files in archive_files_zip.sh implementation script (using zip in this case):

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "$@"
}

Instead of source-ing implementation script directly in the dependent one, you use an injector.sh "container" which wraps both "components":

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

The archive_files dependency has just been injected into dependent script.

You could have injected dependency which implements archive_files using tar or xz.

Example: removing DI

If dependent.sh script used dependencies directly, the approach would be called dependency lookup (which is opposite to dependency injection):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

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

Now the problem is that dependent "component" has to perform initialization itself.

The "component"'s source code is neither clean nor stable because every changes in initialization of dependencies requires new release for "components"'s source code file as well.

Last words

DI is not as largely emphasized and popularized as in Java frameworks.

But it's a generic approach to split concerns of:

  • application development (single source code release lifecycle)
  • application deployment (multiple target environments with independent lifecycles)

Using configuration only with dependency lookup does not help as number of configuration parameters may change per dependency (e.g. new authentication type) as well as number of supported types of dependencies (e.g. new database type).

All the above answers are good, my aim is to explain the concept in a simple way so that anyone without a programming knowledge can also understand concept

Dependency injection is one of the design pattern that help us to create complex systems in a simpler manner.

We can see a wide variety of application of this pattern in our day to day life. Some of the examples are Tape recorder, VCD, CD Drive etc.

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

The above image is an image of Reel-to-reel portable tape recorder, mid-20th century. Source.

The primary intention of a tape recorder machine is to record or playback sound.

While designing a system it require a reel to record or playback sound or music. There are two possibilities for designing this system

  1. we can place the reel inside the machine
  2. we can provide a hook for the reel where it can be placed.

If we use the first one we need to open the machine to change the reel. if we opt for the second one, that is placing a hook for reel, we are getting an added benefit of playing any music by changing the reel. and also reducing the function only to playing whatever in the reel.

Like wise dependency injection is the process of externalizing the dependencies to focus only on the specific functionality of the component so that independent components can be coupled together to form a complex system.

The main benefits we achieved by using dependency injection.

  • High cohesion and loose coupling.
  • Externalizing dependency and looking only on responsibility.
  • Making things as components and to combine to form a large systems with high capabilities.
  • It helps to develop high quality components since they are independently developed they are properly tested.
  • It helps to replace the component with another if one fails.

Now a days these concept forms the basis of well known frameworks in programming world. The Spring Angular etc are the well-known software frameworks built on the top of this concept

Dependency injection is a pattern used to create instances of objects that other objects rely upon without knowing at compile time which class will be used to provide that functionality or simply the way of injecting properties to an object is called dependency injection.

Example for Dependency injection

Previously we are writing code like this

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();
}

With Dependency injection, the dependency injector will take off the instantiation for us

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();
}

You can also read

Difference between Inversion of Control & Dependency Injection

What is dependency Injection?

Dependency Injection(DI) means to decouple the objects which are dependent on each other. Say object A is dependent on Object B so the idea is to decouple these object from each other. We don’t need to hard code the object using new keyword rather sharing dependencies to objects at runtime in spite of compile time. If we talk about

How Dependency Injection works in Spring:

We don’t need to hard code the object using new keyword rather define the bean dependency in the configuration file. The spring container will be responsible for hooking up all.

Inversion of Control (IOC)

IOC is a general concept and it can be expressed in many different ways and Dependency Injection is one concrete example of IOC.

Two types of Dependency Injection:

  1. Constructor Injection
  2. Setter Injection

1. Constructor-based dependency injection:

Constructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on other class.

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. Setter-based dependency injection:

Setter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your 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"/>

NOTE: It is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies. Note that the if we use annotation based than @Required annotation on a setter can be used to make setters as a required dependencies.

The best analogy I can think of is the surgeon and his assistant(s) in an operation theater, where the surgeon is the main person and his assistant who provides the various surgical components when he needs it so that the surgeon can concentrate on the one thing he does best (surgery). Without the assistant the surgeon has to get the components himself every time he needs one.

DI for short, is a technique to remove a common additional responsibility (burden) on components to fetch the dependent components, by providing them to it.

DI brings you closer to the Single Responsibility (SR) principle, like the surgeon who can concentrate on surgery.

When to use DI : I would recommend using DI in almost all production projects ( small/big), particularly in ever changing business environments :)

Why : Because you want your code to be easily testable, mockable etc so that you can quickly test your changes and push it to the market. Besides why would you not when you there are lots of awesome free tools/frameworks to support you in your journey to a codebase where you have more control.

It means that objects should only have as many dependencies as is needed to do their job and the dependencies should be few. Furthermore, an object’s dependencies should be on interfaces and not on “concrete” objects, when possible. (A concrete object is any object created with the keyword new.) Loose coupling promotes greater reusability, easier maintainability, and allows you to easily provide “mock” objects in place of expensive services.

The “Dependency Injection” (DI) is also known as “Inversion of Control” (IoC), can be used as a technique for encouraging this loose coupling.

There are two primary approaches to implementing DI:

  1. Constructor injection
  2. Setter injection

Constructor injection

It’s the technique of passing objects dependencies to its constructor.

Note that the constructor accepts an interface and not concrete object. Also, note that an exception is thrown if the orderDao parameter is null. This emphasizes the importance of receiving a valid dependency. Constructor Injection is, in my opinion, the preferred mechanism for giving an object its dependencies. It is clear to the developer while invoking the object which dependencies need to be given to the “Person” object for proper execution.

Setter Injection

But consider the following example… Suppose you have a class with ten methods that have no dependencies, but you’re adding a new method that does have a dependency on IDAO. You could change the constructor to use Constructor Injection, but this may force you to changes to all constructor calls all over the place. Alternatively, you could just add a new constructor that takes the dependency, but then how does a developer easily know when to use one constructor over the other. Finally, if the dependency is very expensive to create, why should it be created and passed to the constructor when it may only be used rarely? “Setter Injection” is another DI technique that can be used in situations such as this.

Setter Injection does not force dependencies to be passed to the constructor. Instead, the dependencies are set onto public properties exposed by the object in need. As implied previously, the primary motivators for doing this include:

  1. Supporting dependency injection without having to modify the constructor of a legacy class.
  2. Allowing expensive resources or services to be created as late as possible and only when needed.

Here is the example of how the above code would look like:

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;

Example, we have 2 class Client and Service. Client will use Service

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

Without Dependency Injection

Way 1)

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

Way 2)

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

Way 3)

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

1) 2) 3) Using

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

Advantages

  • Simple

Disadvantages

  • Hard for test Client class
  • When we change Service constructor, we need to change code in all place create Service object

Use Dependency Injection

Way 1) Constructor injection

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();
    }
}

Using

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

Way 2) Setter injection

public class Client {
    Service service;

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

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

Using

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

Way 3) Interface injection

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

===

Now, this code is already follow Dependency Injection and it is easier for test Client class.
However, we still use new Service() many time and it is not good when change Service constructor. To prevent it, we can use DI injector like
1) Simple manual 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(...));
    }
}

Using

Service service = Injector.provideService();

2) Use library: For Android dagger2

Advantages

  • Make test easier
  • When you change the Service, you only need to change it in Injector class
  • If you use use Constructor Injection, when you look at constructor of Client, you will see how many dependency of Client class

Disadvantages

  • If you use use Constructor Injection, the Service object is created when Client created, sometime we use function in Client class without use Service so created Service is wasted

Dependency Injection definition

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

A dependency is an object that can be used (Service)
An injection is the passing of a dependency (Service) to a dependent object (Client) that would use it

I think since everyone has written for DI, let me ask a few questions..

  1. When you have a configuration of DI where all the actual implementations(not interfaces) that are going to be injected into a class (for e.g services to a controller) why is that not some sort of hard-coding?
  2. What if I want to change the object at runtime? For example, my config already says when I instantiate MyController, inject for FileLogger as ILogger. But I might want to inject DatabaseLogger.
  3. Everytime I want to change what objects my AClass needs, I need to now look into two places - The class itself and the configuration file. How does that make life easier?
  4. If Aproperty of AClass is not injected, is it harder to mock it out?
  5. Going back to the first question. If using new object() is bad, how come we inject the implementation and not the interface? I think a lot of you are saying we're in fact injecting the interface but the configuration makes you specify the implementation of that interface ..not at runtime .. it is hardcoded during compile time.

This is based on the answer @Adam N posted.

Why does PersonService no longer have to worry about GroupMembershipService? You just mentioned GroupMembership has multiple things(objects/properties) it depends on. If GMService was required in PService, you'd have it as a property. You can mock that out regardless of whether you injected it or not. The only time I'd like it to be injected is if GMService had more specific child classes, which you wouldn't know until runtime. Then you'd want to inject the subclass. Or if you wanted to use that as either singleton or prototype. To be honest, the configuration file has everything hardcoded as far as what subclass for a type (interface) it is going to inject during compile time.

EDIT

A nice comment by Jose Maria Arranz on DI

DI increases cohesion by removing any need to determine the direction of dependency and write any glue code.

False. The direction of dependencies is in XML form or as annotations, your dependencies are written as XML code and annotations. XML and annotations ARE source code.

DI reduces coupling by making all of your components modular (i.e. replacable) and have well-defined interfaces to each other.

False. You do not need a DI framework to build a modular code based on interfaces.

About replaceable: with a very simple .properties archive and Class.forName you can define wich classes can change. If ANY class of your code can be changed, Java is not for you, use an scripting language. By the way: annotations cannot be changed without recompiling.

In my opinion there is one only reason for DI frameworks: boiler plate reduction. With a well done factory system you can do the same, more controlled and more predictable as your preferred DI framework, DI frameworks promise code reduction (XML and annotations are source code too). The problem is this boiler plate reduction is just real in very very simple cases (one instance-per class and similar), sometimes in the real world picking the appropriated service object is not as easy as mapping a class to a singleton object.

Dependency Injection means a way (actually any-way) for one part of code (e.g a class) to have access to dependencies (other parts of code, e.g other classes, it depends upon) in a modular way without them being hardcoded (so they can change or be overriden freely, or even be loaded at another time, as needed)

(and ps , yes it has become an overly-hyped 25$ name for a rather simple, concept), my .25 cents

I know there are already many answers, but I found this very helpful: http://tutorials.jenkov.com/dependency-injection/index.html

No Dependency:

public class MyDao {

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

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

}

Dependency:

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)
  {...}

}

Notice how the DataSourceImpl instantiation is moved into a constructor. The constructor takes four parameters which are the four values needed by the DataSourceImpl. Though the MyDao class still depends on these four values, it no longer satisfies these dependencies itself. They are provided by whatever class creating a MyDao instance.

The popular answers are unhelpful, because they define dependency injection in a way that isn't useful. Let's agree that by "dependency" we mean some pre-existing other object that our object X needs. But we don't say we're doing "dependency injection" when we say

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

We just call that passing parameters into the constructor. We've been doing that regularly ever since constructors were invented.

"Dependency injection" is considered a type of "inversion of control", which means that some logic is taken out of the caller. That isn't the case when the caller passes in parameters, so if that were DI, DI would not imply inversion of control.

DI means there is an intermediate level between the caller and the constructor which manages dependencies. A Makefile is a simple example of dependency injection. The "caller" is the person typing "make bar" on the command line, and the "constructor" is the compiler. The Makefile specifies that bar depends on foo, and it does a

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

before doing a

gcc foo.o bar.o -o bar

The person typing "make bar" doesn't need to know that bar depends on foo. The dependency was injected between "make bar" and gcc.

The main purpose of the intermediate level is not just to pass in the dependencies to the constructor, but to list all the dependencies in just one place, and to hide them from the coder (not to make the coder provide them).

Usually the intermediate level provides factories for the constructed objects, which must provide a role that each requested object type must satisfy. That's because by having an intermediate level that hides the details of construction, you've already incurred the abstraction penalty imposed by factories, so you might as well use factories.

Dependency injection is one possible solution to what could generally be termed the "Dependency Obfuscation" requirement. Dependency Obfuscation is a method of taking the 'obvious' nature out of the process of providing a dependency to a class that requires it and therefore obfuscating, in some way, the provision of said dependency to said class. This is not necessarily a bad thing. In fact, by obfuscating the manner by which a dependency is provided to a class then something outside the class is responsible for creating the dependency which means, in various scenarios, a different implementation of the dependency can be supplied to the class without making any changes to the class. This is great for switching between production and testing modes (eg., using a 'mock' service dependency).

Unfortunately the bad part is that some people have assumed you need a specialized framework to do dependency obfuscation and that you are somehow a 'lesser' programmer if you choose not to use a particular framework to do it. Another, extremely disturbing myth, believed by many, is that dependency injection is the only way of achieving dependency obfuscation. This is demonstrably and historically and obviously 100% wrong but you will have trouble convincing some people that there are alternatives to dependency injection for your dependency obfuscation requirements.

Programmers have understood the dependency obfuscation requirement for years and many alternative solutions have evolved both before and after dependency injection was conceived. There are Factory patterns but there are also many options using ThreadLocal where no injection to a particular instance is needed - the dependency is effectively injected into the thread which has the benefit of making the object available (via convenience static getter methods) to any class that requires it without having to add annotations to the classes that require it and set up intricate XML 'glue' to make it happen. When your dependencies are required for persistence (JPA/JDO or whatever) it allows you to achieve 'tranaparent persistence' much easier and with domain model and business model classes made up purely of POJOs (i.e. no framework specific/locked in annotations).

From the Book, 'Well-Grounded Java Developer: Vital techniques of Java 7 and polyglot programming

DI is a particular form of IoC, whereby the process of finding your dependencies is outside the direct control of your currently executing code.

from Book Apress.Spring.Persistence.with.Hibernate.Oct.2010

The purpose of dependency injection is to decouple the work of resolving external software components from your application business logic.Without dependency injection, the details of how a component accesses required services can get muddled in with the component’s code. This not only increases the potential for errors, adds code bloat, and magnifies maintenance complexities; it couples components together more closely, making it difficult to modify dependencies when refactoring or testing.

Dependency Injection (DI) is one from Design Patterns, which uses the basic feature of OOP - the relationship in one object with another object. While inheritance inherits one object to do more complex and specific another object, relationship or association simply creates a pointer to another object from one object using attribute. The power of DI is in combination with other features of OOP as are interfaces and hiding code. Suppose, we have a customer (subscriber) in the library, which can borrow only one book for simplicity.

Interface of book:

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();
}

Next we can have many kind of books; one of type is fiction:

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);
}
}

Now subscriber can have association to the book:

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) {

}

}

All the three classes can be hidden for it's own implementation. Now we can use this code for 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();
}
}

There are many different ways how to use dependency injection. It is possible to combine it with Singleton, etc., but still in basic it is only association realized by creating attribute of object type inside another object. The usefulness is only and only in feature, that code, which we should write again and again is always prepared and done for us forward. This is why DI so closely binded with Inversion of Control (IoC) which means, that our program passes control another running module, which does injections of beans to our code. (Each object, which can be injected can be signed or considered as a Bean.) For example in Spring it is done by creating and initialization ApplicationContext container, which does this work for us. We simply in our code create the Context and invoke initialization the beans. In that moment injection has been done automatically.

In simple words dependency injection (DI) is the way to remove dependencies or tight coupling between different object. Dependency Injection gives a cohesive behavior to each object.

DI is the implementation of IOC principal of Spring which says "Don't call us we will call you". Using dependency injection programmer doesn't need to create object using the new keyword.

Objects are once loaded in Spring container and then we reuse them whenever we need them by fetching those objects from Spring container using getBean(String beanName) method.

Dependency injection is the heart of the concept related with Spring Framework.While creating the framework of any project spring may perform a vital role,and here dependency injection come in pitcher.

Actually,Suppose in java you created two different classes as class A and class B, and whatever the function are available in class B you want to use in class A, So at that time dependency injection can be used. where you can crate object of one class in other,in the same way you can inject an entire class in another class to make it accessible. by this way dependency can be overcome.

DEPENDENCY INJECTION IS SIMPLY GLUING TWO CLASSES AND AT THE SAME TIME KEEPING THEM SEPARATE.

Dependency Injection (DI) is part of Dependency Inversion Principle (DIP) practice, which is also called Inversion of Control (IoC). Basically you need to do DIP because you want to make your code more modular and unit testable, instead of just one monolithic system. So you start identifying parts of the code that can be separated from the class and abstracted away. Now the implementation of the abstraction need to be injected from outside of the class. Normally this can be done via constructor. So you create a constructor that accepts the abstraction as a parameter, and this is called dependency injection (via constructor). For more explanation about DIP, DI, and IoC container you can read Here

I would propose a slightly different, short and precise definition of what Dependency Injection is, focusing on the primary goal, not on the technical means (following along from here):

Dependency Injection is the process of creating the static, stateless graph of service objects, where each service is parametrised by its dependencies.

The objects that we create in our applications (regardless if we use Java, C# or other object-oriented language) usually fall into one of two categories: stateless, static and global “service objects” (modules), and stateful, dynamic and local “data objects”.

The module graph - the graph of service objects - is typically created on application startup. This can be done using a container, such as Spring, but can also be done manually, by passing parameters to object constructors. Both ways have their pros and cons, but a framework definitely isn’t necessary to use DI in your application.

One requirement is that the services must be parametrised by their dependencies. What this means exactly depends on the language and approach taken in a given system. Usually, this takes the form of constructor parameters, but using setters is also an option. This also means that the dependencies of a service are hidden (when invoking a service method) from the users of the service.

When to use? I would say whenever the application is large enough that encapsulating logic into separate modules, with a dependency graph between the modules gives a gain in readability and explorability of the code.

Dependency Injection is a type of implementation of the "Inversion of Control" principle on which is based Frameworks building.

Frameworks as stated in "Design Pattern" of GoF are classes that implement the main control flow logic raising the developer to do that, in this way Frameworks realize the inversion of control principle.

A way to implement as a technique, and not as class hierarchy, this IoC principle it is just Dependency Injection.

DI consists mainly into delegate the mapping of classes instances and type reference to that instances, to an external "entity": an object, static class, component, framework, etc...

Classes instances are the "dependencies", the external binding of the calling component with the class instance through the reference it is the "injection".

Obviously you can implement this technique in many way as you want from OOP point of view, see for example constructor injection, setter injection, interface injection.

Delegating a third party to carry out the task of match a ref to an object it is very useful when you want to completely separate a component that needs some services from the same services implementation.

In this way, when designing components, you can focus exclusively on their architecture and their specific logic, trusting on interfaces for collaborating with other objects without worry about any type of implementation changes of objects/services used, also if the same object you are using will be totally replaced (obviously respecting the interface).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top