Pregunta

Ya se han publicado varias preguntas con preguntas específicas sobre inyección de dependencia , como cuándo úselo y qué marcos hay para ello. Sin embargo,

¿Qué es la inyección de dependencia y cuándo / por qué debería o no debería usarse?

¿Fue útil?

Solución

Inyección de dependencia es pasar dependencia a otros objetos o framework (inyector de dependencia).

La inyección de dependencia facilita las pruebas. La inyección se puede hacer a través del constructor .

SomeClass () tiene su constructor como sigue:

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

Problema : Si myObject implica tareas complejas como el acceso al disco o el acceso a la red, es difícil realizar una prueba unitaria en SomeClass () . Los programadores deben burlarse de myObject y podrían interceptar la llamada de fábrica.

Solución alternativa :

  • Pasar myObject como argumento para el constructor
public SomeClass (MyClass myObject) {
    this.myObject = myObject;
}

myObject se puede pasar directamente, lo que facilita las pruebas.

  • Una alternativa común es definir un constructor de no hacer nada . La inyección de dependencia se puede hacer a través de setters. (h / t @ MikeVella).
  • Martin Fowler documenta una tercera alternativa (h / t @MarcDix), donde < las clases strong> implementan explícitamente una interfaz para las dependencias que los programadores desean inyectar.

Es más difícil aislar componentes en pruebas unitarias sin inyección de dependencia.

En 2013, cuando escribí esta respuesta, este era un tema importante en el Blog de pruebas de Google . Sigue siendo la mayor ventaja para mí, ya que los programadores no siempre necesitan la flexibilidad adicional en su diseño de tiempo de ejecución (por ejemplo, para el localizador de servicios o patrones similares). Los programadores a menudo necesitan aislar las clases durante las pruebas.

Otros consejos

La mejor definición que he encontrado hasta ahora es una de James Shore :

  

" Inyección de dependencias " es un dólar 25   término para un concepto de 5 centavos. [...]   La inyección de dependencia significa dar un   objetar sus variables de instancia. [...].

Hay un artículo de Martin Fowler que también puede resultar útil.

La inyección de dependencia básicamente proporciona los objetos que un objeto necesita (sus dependencias) en lugar de hacer que los construya él mismo. Es una técnica muy útil para las pruebas, ya que permite burlar o eliminar las dependencias.

Las dependencias se pueden inyectar en los objetos por muchos medios (como la inyección de constructor o la inyección de setter). Incluso se pueden usar marcos de inyección de dependencia especializados (por ejemplo, Spring) para hacer eso, pero ciertamente no son necesarios. No necesita esos marcos para tener inyección de dependencia. Crear instancias y pasar objetos (dependencias) explícitamente es tan buena inyección como inyección por marco.

Encontré este ejemplo divertido en términos de acoplamiento suelto :

Cualquier aplicación se compone de muchos objetos que colaboran entre sí para realizar algunas cosas útiles. Tradicionalmente, cada objeto es responsable de obtener sus propias referencias a los objetos dependientes (dependencias) con las que colabora. Esto lleva a clases altamente acopladas y código difícil de probar.

Por ejemplo, considere un objeto Car .

Un Car depende de las ruedas, el motor, el combustible, la batería, etc. para funcionar. Tradicionalmente definimos la marca de dichos objetos dependientes junto con la definición del objeto Car .

Sin inyección de dependencia (DI):

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

  //The rest
}

Aquí, el objeto Car es responsable de crear los objetos dependientes.

¿Qué sucede si queremos cambiar el tipo de su objeto dependiente, digamos Wheel , después de los pinchazos iniciales NepaliRubberWheel () ? Necesitamos recrear el objeto Car con su nueva dependencia, digamos ChineseRubberWheel () , pero solo el fabricante Car puede hacer eso.

Entonces, ¿qué hace la Inyección de dependencia para ...?

Cuando se usa la inyección de dependencias, los objetos reciben sus dependencias en tiempo de ejecución en lugar de tiempo de compilación (tiempo de fabricación del automóvil) . Para que ahora podamos cambiar la Wheel cuando queramos. Aquí, la dependencia ( wheel ) se puede inyectar en Car en tiempo de ejecución.

Después de usar la inyección de dependencia:

Aquí, estamos inyectando las dependencias (Rueda y batería) en tiempo de ejecución. De ahí el término: Inyección de dependencia.

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

Fuente: Comprensión de la inyección de dependencia

La inyección de dependencia es una práctica en la que los objetos están diseñados de manera que reciben instancias de los objetos de otras piezas de código, en lugar de construirlos internamente. Esto significa que cualquier objeto que implemente la interfaz requerida por el objeto puede ser sustituido sin cambiar el código, lo que simplifica las pruebas y mejora el desacoplamiento.

Por ejemplo, considere estas 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 ) { ... }
} 

En este ejemplo, la implementación de PersonService :: addManager y PersonService :: removeManager necesitaría una instancia de GroupMembershipService para hacer su trabajo Sin la Inyección de dependencias, la forma tradicional de hacerlo sería crear una instancia de GroupMembershipService en el constructor de PersonService y usar ese atributo de instancia en ambas funciones. Sin embargo, si el constructor de GroupMembershipService tiene varias cosas que requiere, o peor aún, hay algunos inicializadores "setters". que deben llamarse en el GroupMembershipService , el código crece con bastante rapidez y el PersonService ahora depende no solo del GroupMembershipService sino también de todo lo demás de eso GroupMembershipService depende. Además, el enlace a GroupMembershipService está codificado en el PersonService , lo que significa que no se puede "simular". un GroupMembershipService para fines de prueba o para usar un patrón de estrategia en diferentes partes de su aplicación.

Con la inyección de dependencia, en lugar de crear una instancia del GroupMembershipService dentro de su PersonService , puede pasarlo al constructor PersonService o de lo contrario, agregue una Propiedad (getter y setter) para establecer una instancia local de la misma. Esto significa que su PersonService ya no tiene que preocuparse por cómo crear un GroupMembershipService , solo acepta los que se le dan y trabaja con ellos. Esto también significa que cualquier cosa que sea una subclase de GroupMembershipService , o que implemente la interfaz GroupMembershipService se puede "inyectar". en el PersonService , y el PersonService no necesita saber sobre el cambio.

La respuesta aceptada es buena, pero me gustaría agregar a esto que DI es muy parecido al clásico evitar las constantes codificadas en el código.

Cuando usa alguna constante como el nombre de una base de datos, la mueve rápidamente desde el interior del código a algún archivo de configuración y pasa una variable que contiene ese valor al lugar donde se necesita. La razón para hacerlo es que estas constantes generalmente cambian con más frecuencia que el resto del código. Por ejemplo, si desea probar el código en una base de datos de prueba.

DI es análogo a esto en el mundo de la programación orientada a objetos. Los valores allí en lugar de los literales constantes son objetos completos, pero la razón para mover el código que los crea a partir del código de clase es similar: los objetos cambian con más frecuencia que el código que los usa. Un caso importante donde se necesita dicho cambio son las pruebas.

Probemos un ejemplo simple con las clases Auto y Engine , cualquier auto necesita un motor para ir a cualquier parte, al menos por ahora. A continuación, cómo se verá el código sin inyección de dependencia.

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

Y para crear una instancia de la clase Car, usaremos el siguiente código:

Car car = new Car();

El problema con este código que hemos acoplado estrechamente a GasEngine y si decidimos cambiarlo a ElectricityEngine, entonces tendremos que reescribir la clase Car. Y cuanto más grande sea la aplicación, más problemas y dolores de cabeza tendremos que agregar y usar un nuevo tipo de motor.

En otras palabras, con este enfoque es que nuestra clase Car de alto nivel depende de la clase GasEngine de nivel inferior que viola el Principio de Inversión de Dependencia (DIP) de SOLID. DIP sugiere que deberíamos depender de abstracciones, no de clases concretas. Entonces, para satisfacer esto, presentamos la interfaz IEngine y reescribimos el código como se muestra a continuación:

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

Ahora nuestra clase Car depende solo de la interfaz IEngine, no de una implementación específica del motor. Ahora, el único truco es cómo creamos una instancia del automóvil y le damos una clase real de motor concreto como GasEngine o ElectricityEngine. Ahí es donde entra Inyección de dependencia .

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

Aquí básicamente inyectamos (pasamos) nuestra dependencia (instancia del motor) al constructor de automóviles. Entonces, nuestras clases tienen un acoplamiento flexible entre los objetos y sus dependencias, y podemos agregar fácilmente nuevos tipos de motores sin cambiar la clase Car.

El principal beneficio de la Inyección de dependencias es que las clases están más débilmente acopladas, porque no tienen dependencias codificadas. Esto sigue el principio de inversión de dependencia, que se mencionó anteriormente. En lugar de hacer referencia a implementaciones específicas, las clases solicitan abstracciones (generalmente interfaces ) que se les proporcionan cuando se construye la clase.

  

Entonces, al final, la inyección de dependencia es solo una técnica para   logrando un acoplamiento flojo entre los objetos y sus dependencias.   En lugar de instanciar directamente dependencias que la clase necesita en   Para realizar sus acciones, se proporcionan dependencias a la clase   (más a menudo) a través de la inyección del constructor.

Además, cuando tenemos muchas dependencias, es una muy buena práctica usar contenedores de Inversión de Control (IoC) que podemos decir qué interfaces deben asignarse a qué implementaciones concretas para todas nuestras dependencias y podemos hacer que resuelva esas dependencias por nosotros cuando construye nuestro objeto. Por ejemplo, podríamos especificar en la asignación para el contenedor IoC que la dependencia IEngine debe asignarse a la clase GasEngine y cuando le pedimos al contenedor IoC una instancia de nuestro Car , construirá automáticamente nuestra clase Car con una dependencia GasEngine transmitida.

ACTUALIZACIÓN: Recientemente vi un curso sobre EF Core de Julie Lerman y también me gustó su breve definición sobre DI.

  

La inyección de dependencia es un patrón para permitir que su aplicación inyecte   objetos sobre la marcha a clases que los necesitan, sin forzarlos   clases para ser responsables de esos objetos. Permite que tu código sea   acoplado más libremente, y Entity Framework Core se conecta a este mismo   sistema de servicios.

Imaginemos que quieres ir a pescar:

  • Sin inyección de dependencia, debe ocuparse de todo usted mismo. Necesita encontrar un bote, comprar una caña de pescar, buscar cebo, etc. Es posible, por supuesto, pero le impone una gran responsabilidad. En términos de software, significa que debe realizar una búsqueda de todas estas cosas.

  • Con la inyección de dependencia, otra persona se encarga de toda la preparación y pone a su disposición el equipo requerido. Recibirá (" será inyectado ") el bote, la caña de pescar y el cebo, todo listo para usar.

Esta es la explicación más simple sobre Inyección de dependencia y Contenedor de inyección de dependencia que he visto:

Sin inyección de dependencia

  • La aplicación necesita Foo (por ejemplo, un controlador), entonces:
  • La aplicación crea Foo
  • La aplicación llama a Foo
    • Foo necesita Bar (por ejemplo, un servicio), entonces:
    • Foo crea Bar
    • Foo llama a Bar
      • Bar necesita Bim (un servicio, un repositorio, & # 8230;), entonces:
      • Bar crea Bim
      • Bar hace algo

Con inyección de dependencia

  • La aplicación necesita Foo, que necesita Bar, que necesita Bim, entonces:
  • La aplicación crea Bim
  • La aplicación crea Bar y le da Bim
  • La aplicación crea Foo y le da Bar
  • La aplicación llama a Foo
    • Foo llama a Bar
      • Bar hace algo

Uso de un recipiente de inyección de dependencia

  • La aplicación necesita Foo entonces:
  • La aplicación obtiene Foo del Contenedor, entonces:
    • El contenedor crea Bim
    • Contenedor crea Bar y le da Bim
    • Container crea Foo y le da Bar
  • La aplicación llama a Foo
    • Foo llama a Bar
      • Bar hace algo

Inyección de dependencia y Contenedores de inyección de dependencia son cosas diferentes:

  • La inyección de dependencia es un método para escribir un mejor código
  • un contenedor DI es una herramienta para ayudar a inyectar dependencias

No necesita un contenedor para realizar la inyección de dependencia. Sin embargo, un contenedor puede ayudarlo.

No " inyección de dependencia " solo significa usar constructores parametrizados y setters públicos?

El artículo de James Shore muestra los siguientes ejemplos para comparación .

Constructor sin inyección de dependencia:

public class Example { 
  private DatabaseThingie myDatabase; 

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

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

Constructor con inyección de dependencia:

public class Example { 
  private DatabaseThingie myDatabase; 

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

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

¿Qué es la inyección de dependencia (DI)?

Como han dicho otros, Dependency Injection (DI) elimina la responsabilidad de la creación directa y la gestión de la vida útil de otras instancias de objeto de las que depende nuestra clase de interés (clase de consumidor) ( en el sentido UML ). En su lugar, estas instancias se pasan a nuestra clase de consumidor, generalmente como parámetros de constructor o mediante establecedores de propiedades (la gestión de la instancia del objeto de dependencia y el paso a la clase de consumidor generalmente se realiza mediante una Inversión de control (IoC) contenedor, pero ese es otro tema).

DI, DIP y SÓLIDO

Específicamente, en el paradigma de principios SOLID del diseño orientado a objetos de Robert C Martin a>, DI es una de las posibles implementaciones del Principio de inversión de dependencia (DIP) . El DIP es el D del mantra SOLID - otro DIP Las implementaciones incluyen el Localizador de servicios y los patrones de complementos.

El objetivo del DIP es desacoplar dependencias apretadas y concretas entre clases y, en cambio, aflojar el acoplamiento mediante una abstracción, que se puede lograr a través de una interfaz , abstract clase o clase virtual pura , según el idioma y el enfoque utilizado.

Sin el DIP, nuestro código (lo he llamado 'clase consumidora') está directamente acoplado a una dependencia concreta y a menudo también está cargado con la responsabilidad de saber cómo obtener y administrar una instancia de esta dependencia, es decir, conceptualmente:

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

Mientras que después de la aplicación del DIP, el requisito se afloja y la preocupación de obtener y administrar la vida útil de la dependencia Foo se ha eliminado:

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

¿Por qué usar DIP (y DI)?

El desacoplamiento de dependencias entre clases de esta manera permite la sustitución fácil de estas clases de dependencia con otras implementaciones que también cumplen los requisitos previos de la abstracción (por ejemplo, la dependencia se puede cambiar con otra implementación de la misma interfaz ) Además, como otros han mencionado, posiblemente la razón más común para desacoplar clases a través del DIP es permitir que una clase consumidora se pruebe de forma aislada, ya que estas mismas dependencias ahora se pueden tropezar y / o burlar.

Una consecuencia de DI es que la gestión de la vida útil de las instancias de objetos de dependencia ya no está controlada por una clase consumidora, ya que el objeto de dependencia ahora se pasa a la clase consumidora (mediante inyección de constructor o setter).

Esto se puede ver de diferentes maneras:

  • Si es necesario mantener el control de la vida útil de las dependencias por parte de la clase consumidora, se puede restablecer el control inyectando una fábrica (abstracta) para crear las instancias de clase de dependencia, en la clase de consumidor. El consumidor podrá obtener instancias a través de un Crear en la fábrica según sea necesario, y eliminar estas instancias una vez que estén completas.
  • O, el control de la vida útil de las instancias de dependencia se puede ceder a un contenedor de IoC (más sobre esto a continuación).

¿Cuándo usar DI?

  • Donde probablemente sea necesario sustituir una dependencia por una implementación equivalente,
  • En cualquier momento en que necesite probar la unidad de los métodos de una clase en forma aislada de sus dependencias,
  • Donde la incertidumbre de la vida útil de una dependencia puede justificar la experimentación (por ejemplo, Hey, MyDepClass es seguro para subprocesos, ¿qué pasa si lo convertimos en un singleton e inyectamos la misma instancia a todos los consumidores?) >

Ejemplo

Aquí hay una implementación simple de C #. Dada la siguiente clase de consumo:

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

Aunque aparentemente inocuo, tiene dos dependencias static en otras dos clases, System.DateTime y System.Console , que no solo limitan las opciones de salida de registro (iniciar sesión en la consola no valdrá nada si nadie está mirando), pero lo que es peor, es difícil de probar automáticamente dada la dependencia de un reloj de sistema no determinista.

Sin embargo, podemos aplicar DIP a esta clase, resumiendo la preocupación de la marca de tiempo como una dependencia, y acoplando MyLogger solo a una interfaz simple:

public interface IClock
{
    DateTime Now { get; }
}

También podemos aflojar la dependencia de Console a una abstracción, como un TextWriter . La inyección de dependencia se implementa típicamente como inyección constructor (pasando una abstracción a una dependencia como parámetro al constructor de una clase consumidora) o Setter Injection (pasando la dependencia a través de un setXyz () setter o una propiedad .Net con {set;} definido). Se prefiere la inyección de constructor, ya que esto garantiza que la clase estará en un estado correcto después de la construcción, y permite que los campos de dependencia internos se marquen como readonly (C #) o final ( Java). Entonces, usando la inyección del constructor en el ejemplo anterior, esto nos deja con:

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

(Se debe proporcionar un Clock concreto, que por supuesto podría volver a DateTime.Now , y las dos dependencias deben ser proporcionadas por un contenedor IoC a través del constructor inyección)

Se puede construir una prueba unitaria automatizada, que demuestra definitivamente que nuestro registrador funciona correctamente, ya que ahora tenemos control sobre las dependencias, el tiempo, y podemos espiar la salida escrita:

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

Próximos pasos

La inyección de dependencia está invariablemente asociada con un Contenedor de inversión de control (IoC) , para inyectar ( proporcionar) las instancias de dependencia concretas, y gestionar instancias de vida útil. Durante el proceso de configuración / arranque, los contenedores IoC permiten definir lo siguiente:

  • asignación entre cada abstracción y la implementación concreta configurada (por ejemplo, " cada vez que un consumidor solicita un IBar , devuelve una instancia de ConcreteBar " )
  • Se pueden configurar
  • políticas para la gestión de la vida útil de cada dependencia, p. para crear un nuevo objeto para cada instancia de consumidor, para compartir una instancia de dependencia singleton entre todos los consumidores, para compartir la misma instancia de dependencia solo a través del mismo hilo, etc.
  • En .Net, los contenedores IoC conocen los protocolos como IDisposable y asumirán la responsabilidad de las dependencias de Disposición en línea con la gestión de vida útil configurada.

Normalmente, una vez que los contenedores de IoC se han configurado / arrancado, funcionan sin problemas en segundo plano, lo que permite al codificador centrarse en el código disponible en lugar de preocuparse por las dependencias.

  

La clave del código compatible con DI es evitar el acoplamiento estático de clases y no utilizar new () para la creación de dependencias

Como en el ejemplo anterior, el desacoplamiento de dependencias requiere un esfuerzo de diseño, y para el desarrollador, se necesita un cambio de paradigma para romper el hábito de new ing dependencias directamente, y en su lugar confiar en el contenedor para gestionar dependencias.

Pero los beneficios son muchos, especialmente en la capacidad de evaluar a fondo su clase de interés.

Nota : La creación / mapeo / proyección (a través de new .. () ) de POCO / POJO / DTO de serialización / Gráficos de entidades / Proyecciones JSON anónimas et al. es decir, "Datos solamente" clases o registros: los métodos utilizados o devueltos desde no se consideran Dependencias (en el sentido de UML) y no están sujetos a DI. Usar new para proyectar esto está bien.

Para hacer que el concepto de inyección de dependencia sea simple de entender. Tomemos un ejemplo de botón de interruptor para alternar (activar / desactivar) una bombilla.

Sin inyección de dependencia

Switch necesita saber de antemano a qué bombilla estoy conectado (dependencia codificada). Entonces,

Interruptor - > PermanentBulb // el interruptor está directamente conectado a la bombilla permanente, las pruebas no son posibles fácilmente

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

Con inyección de dependencia

Switch solo sabe que necesito encender / apagar la bombilla que me pasen. Entonces,

Interruptor - > Bulb1 OR Bulb2 OR NightBulb (dependencia inyectada)

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

Modificación de James Ejemplo de interruptor y bombilla:

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

El objetivo de la inyección de dependencia (DI) es mantener el código fuente de la aplicación limpio y estable :

  • clean del código de inicialización de dependencia
  • estable independientemente de la dependencia utilizada

Prácticamente, cada patrón de diseño separa las preocupaciones para hacer que los cambios futuros afecten a los archivos mínimos.

El dominio específico de DI es la delegación de configuración e inicialización de dependencia.

Ejemplo: DI con script de shell

Si ocasionalmente trabaja fuera de Java, recuerde cómo source se usa a menudo en muchos lenguajes de scripting (Shell, Tcl, etc.) o incluso import en Python mal utilizado para este propósito).

Considere la secuencia de comandos simple dependen.sh :

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

El script depende: no se ejecutará con éxito por sí solo ( archive_files no está definido).

Usted define archive_files en el script de implementación archive_files_zip.sh (usando zip en este caso):

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

En lugar de source -ing script de implementación directamente en el dependiente, utiliza un injector.sh " container " que envuelve ambos "componentes":

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

El archive_files dependencia acaba de ser inyectado en el script dependiente .

Podría haber inyectado dependencia que implementa archive_files usando tar o xz .

Ejemplo: eliminar DI

Si el script dependen.sh usaba dependencias directamente, el enfoque se llamaría búsqueda de dependencia (que es opuesto a inyección de dependencia ):

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

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

Ahora el problema es ese '' componente '' dependiente tiene que realizar la inicialización en sí misma.

El código fuente del " componente " no es limpio ni estable porque cada cambio en la inicialización de dependencias requiere una nueva versión para el código fuente de " componentes " archivo también.

Últimas palabras

DI no está tan enfatizado y popularizado en gran medida como en los frameworks de Java.

Pero es un enfoque genérico para dividir las preocupaciones de:

  • desarrollo de aplicaciones ( ciclo de vida de lanzamiento de código fuente único )
  • implementación ( múltiples entornos objetivo con ciclos de vida independientes)

El uso de la configuración solo con búsqueda de dependencias no ayuda, ya que el número de parámetros de configuración puede cambiar por dependencia (por ejemplo, nuevo tipo de autenticación), así como el número de tipos de dependencias compatibles (por ejemplo, nuevo tipo de base de datos).

Todas las respuestas anteriores son buenas, mi objetivo es explicar el concepto de una manera simple para que cualquier persona sin conocimientos de programación también pueda entender el concepto

La inyección de dependencia es uno de los patrones de diseño que nos ayudan a crear sistemas complejos de una manera más simple.

Podemos ver una amplia variedad de aplicaciones de este patrón en nuestro día a día. Algunos de los ejemplos son grabadora de cinta, VCD, unidad de CD, etc.

 Grabadora de cinta portátil de carrete a mediados del siglo XX.

La imagen de arriba es una imagen de una grabadora de cinta portátil de carrete, de mediados del siglo XX. Fuente .

La intención principal de una máquina grabadora es grabar o reproducir sonido.

Al diseñar un sistema, se requiere un carrete para grabar o reproducir sonido o música. Hay dos posibilidades para diseñar este sistema

  1. podemos colocar el carrete dentro de la máquina
  2. podemos proporcionar un gancho para el carrete donde se puede colocar.

Si usamos el primero, necesitamos abrir la máquina para cambiar el carrete. Si optamos por el segundo, que es colocar un gancho para el carrete, obtendremos un beneficio adicional de reproducir cualquier música al cambiar el carrete. y también reduciendo la función solo para jugar lo que sea en el carrete.

De la misma manera, la inyección de dependencias es el proceso de externalizar las dependencias para enfocarse solo en la funcionalidad específica del componente para que los componentes independientes se puedan acoplar para formar un sistema complejo.

Los principales beneficios que logramos mediante el uso de inyección de dependencia.

  • Alta cohesión y acoplamiento flojo.
  • Externalizar la dependencia y mirar solo la responsabilidad.
  • Hacer las cosas como componentes y combinarlas para formar grandes sistemas con altas capacidades.
  • Ayuda a desarrollar componentes de alta calidad, ya que se desarrollan de forma independiente y se prueban adecuadamente.
  • Ayuda a reemplazar el componente con otro si uno falla.

Hoy en día, este concepto forma la base de marcos bien conocidos en el mundo de la programación. Spring Angular, etc., son los marcos de software conocidos creados sobre la base de este concepto

La inyección de dependencia es un patrón utilizado para crear instancias de objetos de los que dependen otros objetos sin saber en el momento de la compilación qué clase se usará para proporcionar esa funcionalidad o simplemente la forma de inyectar propiedades a un objeto se llama inyección de dependencia.

Ejemplo de inyección de dependencia

Anteriormente estábamos escribiendo código como este

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 la inyección de dependencia, el inyector de dependencia nos quitará la instancia

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

También puedes leer

Diferencia entre inversión de control y amp; Inyección de dependencia

¿Qué es la inyección de dependencia?

La inyección de dependencia (DI) significa desacoplar los objetos que dependen unos de otros. Digamos que el objeto A depende del objeto B, por lo que la idea es desacoplar estos objetos entre sí. No necesitamos codificar el objeto con una nueva palabra clave, en lugar de compartir dependencias con los objetos en tiempo de ejecución a pesar del tiempo de compilación. Si hablamos de

Cómo funciona la inyección de dependencias en primavera:

No necesitamos codificar el objeto con una nueva palabra clave sino definir la dependencia del bean en el archivo de configuración. El contenedor de resorte será responsable de conectar todo.

Inversión de control (COI)

El COI es un concepto general y se puede expresar de muchas maneras diferentes, y la inyección de dependencia es un ejemplo concreto de COI.

Dos tipos de inyección de dependencia:

  1. Inyección de constructor
  2. Inyección de Setter

1. Inyección de dependencia basada en constructor:

La DI basada en constructor se logra cuando el contenedor invoca un constructor de clase con varios argumentos, cada uno de los cuales representa una dependencia de otra clase.

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. Inyección de dependencia basada en Setter:

La DI basada en Setter se logra mediante los métodos de establecimiento de llamadas de contenedor en sus beans después de invocar un constructor sin argumentos o un método de fábrica estático sin argumentos para instanciar su 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: Es una buena regla general usar argumentos de constructor para dependencias obligatorias y establecedores para dependencias opcionales. Tenga en cuenta que si usamos una anotación basada en la anotación @Required en un setter se puede usar para hacer setters como dependencias requeridas.

La mejor analogía que se me ocurre es el cirujano y su (s) asistente (s) en un quirófano, donde el cirujano es la persona principal y su asistente que proporciona los diversos componentes quirúrgicos cuando los necesita para que el cirujano pueda concentrarse en la única cosa que hace mejor (cirugía). Sin el asistente, el cirujano tiene que obtener los componentes él mismo cada vez que necesita uno.

DI para abreviar, es una técnica para eliminar una responsabilidad adicional común (carga) sobre los componentes para obtener los componentes dependientes, proporcionándolos.

DI lo acerca al principio de responsabilidad única (SR), como el cirujano que puede concentrarse en la cirugía .

Cuándo usar DI: recomendaría usar DI en casi todos los proyectos de producción (pequeños / grandes), particularmente en entornos empresariales en constante cambio :)

Por qué: porque desea que su código sea fácilmente comprobable, simulable, etc. para que pueda probar rápidamente sus cambios y llevarlo al mercado. Además, ¿por qué no lo harías si hay muchas herramientas / marcos gratuitos increíbles para apoyarte en tu viaje a una base de código donde tienes más control?

Significa que los objetos solo deberían tener tantas dependencias como sea necesario para hacer su trabajo y las dependencias deberían ser pocas. Además, las dependencias de un objeto deben estar en interfaces y no en objetos "concretos", cuando sea posible. (Un objeto concreto es cualquier objeto creado con la palabra clave new.) El acoplamiento flojo promueve una mayor reutilización, una capacidad de mantenimiento más fácil y le permite proporcionar fácilmente objetos "simulados" en lugar de servicios caros.

La "Inyección de dependencia" (DI) también se conoce como "Inversión de control" (IoC), se puede utilizar como una técnica para fomentar este acoplamiento flojo.

Hay dos enfoques principales para implementar DI:

  1. Inyección de constructor
  2. Inyección Setter

Inyección del constructor

Es la técnica de pasar dependencias de objetos a su constructor.

Tenga en cuenta que el constructor acepta una interfaz y no un objeto concreto. Además, tenga en cuenta que se produce una excepción si el parámetro de orden de venta es nulo. Esto enfatiza la importancia de recibir una dependencia válida. La inyección de constructor es, en mi opinión, el mecanismo preferido para dar a un objeto sus dependencias. Es claro para el desarrollador al invocar al objeto qué dependencias deben darse al objeto "Persona" para una ejecución adecuada.

Inyección de Setter

Pero considere el siguiente ejemplo ... Suponga que tiene una clase con diez métodos que no tienen dependencias, pero está agregando un nuevo método que sí depende de IDAO. Puede cambiar el constructor para usar la inyección de constructor, pero esto puede obligarlo a cambiar todas las llamadas de constructor por todas partes. Alternativamente, podría agregar un nuevo constructor que tome la dependencia, pero entonces, ¿cómo sabe un desarrollador fácilmente cuándo usar un constructor sobre el otro? Finalmente, si la dependencia es muy costosa de crear, ¿por qué debería crearse y pasarse al constructor cuando solo puede usarse raramente? La "inyección Setter" es otra técnica de DI que se puede utilizar en situaciones como esta.

Setter Injection no obliga a pasar dependencias al constructor. En cambio, las dependencias se establecen en propiedades públicas expuestas por el objeto que lo necesita. Como se indicó anteriormente, los principales motivadores para hacer esto incluyen:

  1. Soporte de inyección de dependencia sin tener que modificar el constructor de una clase heredada.
  2. Permitir la creación de recursos o servicios costosos lo más tarde posible y solo cuando sea necesario.

Aquí está el ejemplo de cómo se vería el código anterior:

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;

Ejemplo, tenemos 2 clases Client y Service . Client usará Service

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

Sin inyección de dependencia

Forma 1)

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

Forma 2)

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

Forma 3)

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

1) 2) 3) Uso

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

Ventajas

  • Simple

Desventajas

  • Difícil para la prueba Cliente clase
  • Cuando cambiamos el constructor Service , necesitamos cambiar el código en todo lugar para crear el objeto Service

Usar inyección de dependencia

Forma 1) Inyección del constructor

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

Uso

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

Forma 2) Inyección de Setter

public class Client {
    Service service;

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

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

Uso

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

Forma 3) Inyección de interfaz

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

===

Ahora, este código ya sigue a Inyección de dependencia y es más fácil para probar la clase Client .
Sin embargo, todavía usamos new Service () muchas veces y no es bueno cuando se cambia el constructor Service . Para evitarlo, podemos usar un inyector DI como
1) Manual simple 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) Usar biblioteca: para Android dagger2

Ventajas

  • Hacer la prueba más fácil
  • Cuando cambia el Servicio , solo necesita cambiarlo en la clase de inyector
  • Si usa el uso Inyección del constructor , cuando observe el constructor del Cliente , verá cuántas dependencias de la clase Cliente

Desventajas

  • Si usa el uso Inyección del constructor , el objeto Servicio se crea cuando se crea Client , a veces usamos la función en Client clase sin uso Servicio así creado Servicio se desperdicia

Definición de inyección de dependencia

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

  

Una dependencia es un objeto que se puede usar ( Servicio )
  Una inyección es el paso de una dependencia ( Service ) a un objeto dependiente ( Client ) que lo usaría

Creo que como todos han escrito para DI, déjenme hacer algunas preguntas ...

  1. Cuando tiene una configuración de DI donde todas las implementaciones reales (no las interfaces) que se van a inyectar en una clase (por ejemplo, servicios a un controlador) ¿por qué no se trata de algún tipo de codificación?
  2. ¿Qué sucede si quiero cambiar el objeto en tiempo de ejecución? Por ejemplo, mi configuración ya dice que cuando ejecuto MyController, inyecto FileLogger como ILogger. Pero podría querer inyectar DatabaseLogger.
  3. Cada vez que quiero cambiar qué objetos necesita mi AClass, ahora necesito mirar en dos lugares: la clase en sí y el archivo de configuración. ¿Cómo hace eso la vida más fácil?
  4. Si no se inyecta una propiedad de AClass, ¿es más difícil burlarse de ella?
  5. Volviendo a la primera pregunta. Si usar new object () es malo, ¿cómo podemos inyectar la implementación y no la interfaz? Creo que muchos de ustedes dicen que de hecho estamos inyectando la interfaz, pero la configuración les hace especificar la implementación de esa interfaz ... no en tiempo de ejecución ... está codificada durante el tiempo de compilación.

Esto se basa en la respuesta publicada por @Adam N.

¿Por qué PersonService ya no tiene que preocuparse por GroupMembershipService? Usted acaba de mencionar que GroupMembership tiene varias cosas (objetos / propiedades) de las que depende. Si se requiere GMService en PService, lo tendría como una propiedad. Puede burlarse de eso independientemente de si lo inyectó o no. La única vez que me gustaría que se inyectara es si GMService tuviera clases secundarias más específicas, que no sabría hasta el tiempo de ejecución. Entonces querrás inyectar la subclase. O si quisieras usar eso como singleton o prototipo. Para ser sincero, el archivo de configuración tiene todo codificado en cuanto a qué subclase para un tipo (interfaz) va a inyectar durante el tiempo de compilación.

EDITAR

Un buen comentario de Jose Maria Arranz sobre DI

DI aumenta la cohesión al eliminar cualquier necesidad de determinar la dirección de dependencia y escribir cualquier código de pegamento.

Falso. La dirección de las dependencias es en forma XML o como anotaciones, sus dependencias se escriben como código XML y anotaciones. XML y anotaciones SON código fuente.

DI reduce el acoplamiento al hacer que todos sus componentes sean modulares (es decir, reemplazables) y tengan interfaces bien definidas entre sí.

Falso. No necesita un marco DI para construir un código modular basado en interfaces.

Acerca de reemplazable: con un archivo .properties muy simple y Class.forName puede definir qué clases pueden cambiar. Si se puede cambiar CUALQUIER clase de su código, Java no es para usted, use un lenguaje de script. Por cierto: las anotaciones no se pueden cambiar sin volver a compilar.

En mi opinión, hay una única razón para los marcos DI: la reducción de la placa de caldera. Con un sistema de fábrica bien hecho, puede hacer lo mismo, más controlado y más predecible que su marco DI preferido, los marcos DI prometen reducción de código (XML y las anotaciones también son código fuente). El problema es que esta reducción de la placa de caldera es real en casos muy simples (una instancia por clase y similar), a veces en el mundo real elegir el objeto de servicio apropiado no es tan fácil como asignar una clase a un objeto singleton.

Inyección de dependencia significa una forma (en realidad de cualquier manera ) para una parte del código (p. ej., una clase) para tener acceso a las dependencias (otras partes del código, p. ej., otras clases, de las que depende) de forma modular sin que estén codificadas (para que puedan cambiar o anularse libremente, o incluso cargarse en otro momento) según sea necesario)

(y ps, sí, se ha convertido en un nombre excesivamente publicitado de 25 $ para un concepto bastante simple) , mis .25 cents

Sé que ya hay muchas respuestas, pero encontré esto muy útil: http: //tutorials.jenkov. com / dependency-injection / index.html

Sin dependencia:

public class MyDao {

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

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

}

Dependencia:

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

}

Observe cómo la instanciación DataSourceImpl se traslada a un constructor. El constructor toma cuatro parámetros, que son los cuatro valores que necesita el DataSourceImpl . Aunque la clase MyDao todavía depende de estos cuatro valores, ya no satisface estas dependencias. Los proporciona cualquier clase que cree una instancia de MyDao .

Las respuestas populares no son útiles, porque definen la inyección de dependencia de una manera que no es útil. Acordemos que por " dependencia " nos referimos a algún otro objeto preexistente que nuestro objeto X necesita. Pero no decimos que estamos haciendo "inyección de dependencia" cuando decimos

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

Simplemente llamamos a eso pasar parámetros al constructor. Lo hemos estado haciendo regularmente desde que se inventaron los constructores.

" Inyección de dependencia " se considera un tipo de `` inversión de control '', lo que significa que la persona que llama extrae algo de lógica. Ese no es el caso cuando la persona que llama pasa parámetros, por lo que si fuera DI, DI no implicaría una inversión de control.

DI significa que hay un nivel intermedio entre el llamador y el constructor que gestiona las dependencias. Un Makefile es un ejemplo simple de inyección de dependencia. El " llamante " es la persona que escribe " make bar " en la línea de comando y el constructor " es el compilador El Makefile especifica que la barra depende de foo, y hace un

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

antes de hacer un

gcc foo.o bar.o -o bar

La persona que escribe " make bar " no necesita saber que la barra depende de foo. La dependencia se inyectó entre " make bar " y gcc.

El propósito principal del nivel intermedio no es solo pasar las dependencias al constructor, sino enumerar todas las dependencias en un solo lugar y ocultarlas del codificador (no hacer que el codificador se los proporcione).

Por lo general, el nivel intermedio proporciona fábricas para los objetos construidos, que deben proporcionar una función que cada tipo de objeto solicitado debe cumplir. Esto se debe a que al tener un nivel intermedio que oculta los detalles de la construcción, ya ha incurrido en la penalización por abstracción impuesta por las fábricas, por lo que también podría usar fábricas.

La inyección de dependencia es una posible solución a lo que generalmente podría denominarse "Ofuscación de dependencia". requisito. La ofuscación de dependencia es un método para eliminar la naturaleza 'obvia' del proceso de proporcionar una dependencia a una clase que lo requiere y, por lo tanto, ofuscar, de alguna manera, la provisión de dicha dependencia a dicha clase. Este no es necesariamente algo malo. De hecho, al ofuscar la manera en que se proporciona una dependencia a una clase, entonces algo fuera de la clase es responsable de crear la dependencia, lo que significa que, en varios escenarios, se puede proporcionar una implementación diferente de la dependencia a la clase sin realizar ningún cambio a la clase. Esto es ideal para cambiar entre los modos de producción y prueba (p. Ej., Utilizando una dependencia de servicio 'simulada').

Desafortunadamente, la parte mala es que algunas personas han asumido que necesita un marco especializado para ofuscar la dependencia y que de alguna manera es un programador 'menor' si elige no usar un marco particular para hacerlo. Otro mito extremadamente perturbador, que muchos creen, es que la inyección de dependencia es la única forma de lograr la ofuscación de dependencia. Esto es demostrable e histórica y obviamente 100% incorrecto, pero tendrá problemas para convencer a algunas personas de que existen alternativas a la inyección de dependencia para sus requisitos de ofuscación de dependencia.

Los programadores han entendido el requisito de ofuscación de dependencia durante años y muchas soluciones alternativas han evolucionado tanto antes como después de concebir la inyección de dependencia. Existen patrones de fábrica, pero también hay muchas opciones que usan ThreadLocal donde no se necesita una inyección en una instancia particular: la dependencia se inyecta efectivamente en el hilo que tiene el beneficio de hacer que el objeto esté disponible (a través de métodos convenientes de obtención estática) para cualquier clase que lo requiera sin tener que agregar anotaciones a las clases que lo requieren y configurar intrincados 'pegamentos' XML para que esto suceda. Cuando sus dependencias son necesarias para la persistencia (JPA / JDO o lo que sea), le permite lograr una 'persistencia transnaparente' mucho más fácil y con clases de modelo de dominio y modelo de negocio formadas exclusivamente por POJO (es decir, sin marco específico / bloqueado en anotaciones).

Del libro, ' Desarrollador Java bien fundamentado: técnicas vitales de Java 7 y políglota programación

  

DI es una forma particular de IoC, por el cual el proceso de encontrar sus dependencias es   fuera del control directo de su código actualmente en ejecución.

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

  

El propósito de la inyección de dependencia es desacoplar el trabajo de   resolviendo componentes de software externos de su negocio de aplicaciones   lógica Sin inyección de dependencia, los detalles de cómo un componente   los accesos a los servicios requeridos pueden confundirse con los componentes   código. Esto no solo aumenta la posibilidad de errores, agrega código   hincha y magnifica las complejidades de mantenimiento; acopla componentes   juntos más de cerca, lo que dificulta la modificación de dependencias cuando   refactorización o prueba.

Dependency Injection (DI) es uno de Design Patterns, que utiliza la característica básica de OOP: la relación en un objeto con otro objeto. Mientras que la herencia hereda un objeto para hacer otro objeto más complejo y específico, la relación o asociación simplemente crea un puntero a otro objeto desde un objeto usando un atributo. El poder de DI está en combinación con otras características de OOP como son las interfaces y el código oculto. Supongamos que tenemos un cliente (suscriptor) en la biblioteca, que solo puede tomar prestado un libro por simplicidad.

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

Luego podemos tener muchos tipos de libros; uno de tipo es ficción:

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

Ahora el suscriptor puede tener asociación con el 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) {

}

}

Las tres clases se pueden ocultar para su propia implementación. Ahora podemos usar este código para 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();
}
}

Hay muchas formas diferentes de usar la inyección de dependencia. Es posible combinarlo con Singleton, etc., pero aún así, en la base, solo es una asociación realizada al crear un atributo de tipo de objeto dentro de otro objeto. La utilidad es única y única en la característica, ese código, que debemos escribir una y otra vez, siempre está preparado y hecho para que lo enviemos. Esta es la razón por la cual DI se vinculó tan estrechamente con la Inversión de control (IoC), lo que significa que nuestro programa pasa el control de otro módulo en ejecución, que inyecta frijoles a nuestro código. (Cada objeto, que se puede inyectar, se puede firmar o considerar como un Bean). Por ejemplo, en Spring se hace mediante la creación e inicialización del contenedor ApplicationContext , que nos sirve. Simplemente en nuestro código creamos el Contexto e invocamos la inicialización de los beans. En ese momento, la inyección se realizó automáticamente.

En palabras simples, la inyección de dependencias (DI) es la forma de eliminar dependencias o un acoplamiento estrecho entre diferentes objetos. La inyección de dependencia da un comportamiento coherente a cada objeto.

DI es la implementación del director del COI de Spring que dice "No nos llame, lo llamaremos". El uso del programador de inyección de dependencias no necesita crear objetos usando la nueva palabra clave.

Los objetos se cargan una vez en el contenedor Spring y luego los reutilizamos cada vez que los necesitamos buscando esos objetos desde el contenedor Spring utilizando el método getBean (String beanName).

La inyección de dependencia es el corazón del concepto relacionado con Spring Framework. Mientras que la creación del marco de cualquier proyecto Spring puede desempeñar un papel vital, y aquí la inyección de dependencia viene en el lanzador.

En realidad, supongamos que en Java creó dos clases diferentes como clase A y clase B, y cualquiera que sea la función disponible en la clase B que quiera usar en la clase A, entonces en ese momento se puede usar la inyección de dependencia. donde puede crear objetos de una clase en otra, de la misma manera que puede inyectar una clase completa en otra clase para hacerla accesible. de esta manera se puede superar la dependencia.

LA INYECCIÓN DE DEPENDENCIA SIMPLEMENTE PEGA DOS CLASES Y AL MISMO TIEMPO MANTÉNDOLAS SEPARADAS.

La inyección de dependencia (DI) es parte de la práctica del Principio de inversión de dependencia (DIP), que también se llama Inversión de control (IoC). Básicamente, debe hacer DIP porque desea hacer que su código sea más modular y comprobable por unidad, en lugar de un solo sistema monolítico. Entonces comienza a identificar partes del código que pueden separarse de la clase y extraerse. Ahora, la implementación de la abstracción debe ser inyectada desde fuera de la clase. Normalmente esto se puede hacer a través del constructor. Entonces crea un constructor que acepta la abstracción como un parámetro, y esto se llama inyección de dependencia (a través del constructor). Para obtener más explicaciones sobre el contenedor DIP, DI y IoC, puede leer Aquí

Propondría una definición ligeramente diferente, breve y precisa de lo que es la inyección de dependencia, centrándome en el objetivo principal, no en los medios técnicos (siguiendo aquí ):

  

La inyección de dependencia es el proceso de creación de la estática, sin estado   gráfico de objetos de servicio, donde cada servicio está parametrizado por su   dependencias.

Los objetos que creamos en nuestras aplicaciones (independientemente de si usamos Java, C # u otro lenguaje orientado a objetos) generalmente se dividen en una de dos categorías: sin estado, estático y global & # 8220; objetos de servicio & # 8221; (módulos) y objetos de datos con estado, dinámicos y locales & # 8220; & # 8221 ;.

El gráfico del módulo, el gráfico de los objetos de servicio, generalmente se crea al iniciar la aplicación. Esto se puede hacer usando un contenedor, como Spring, pero también se puede hacer manualmente, pasando parámetros a los constructores de objetos. Ambas formas tienen sus pros y sus contras, pero definitivamente no es necesario un marco para usar DI en su aplicación.

Un requisito es que los servicios deben ser parametrizados por sus dependencias. Lo que esto significa exactamente depende del lenguaje y el enfoque adoptado en un sistema dado. Por lo general, esto toma la forma de parámetros de constructor, pero usar setters también es una opción. Esto también significa que las dependencias de un servicio están ocultas (al invocar un método de servicio) de los usuarios del servicio.

¿Cuándo usarlo? Yo diría que siempre que la aplicación sea lo suficientemente grande como para encapsular la lógica en módulos separados, con un gráfico de dependencia entre los módulos se obtiene una mejora en la legibilidad y explorabilidad del código.

Inyección de dependencia es un tipo de implementación de " Inversión de control " principio en el que se basa la construcción de marcos.

Marcos como se indica en " Patrón de diseño " de GoF son clases que implementan la lógica de flujo de control principal, lo que hace que el desarrollador haga eso, de esta manera Frameworks se da cuenta del principio de inversión de control.

Una forma de implementar como técnica, y no como jerarquía de clases, este principio de IoC es solo Inyección de Dependencia.

DI consiste principalmente en delegar la asignación de instancias de clases y escribir referencias a esas instancias, a una '' entidad '' externa: un objeto, clase estática, componente, marco, etc ...

Las instancias de clases son las " dependencias " ;, el enlace externo del componente de llamada con la instancia de clase a través de la referencia es el " < em> inyección " ;.

Obviamente, puede implementar esta técnica de la manera que desee desde el punto de vista de OOP; consulte, por ejemplo, inyección de constructor , inyección de setter , inyección de interfaz .

Delegar a un tercero para llevar a cabo la tarea de hacer coincidir una referencia con un objeto es muy útil cuando desea separar completamente un componente que necesita algunos servicios de la misma implementación de servicios.

De esta forma, al diseñar componentes, puede centrarse exclusivamente en su arquitectura y su lógica específica, confiando en las interfaces para colaborar con otros objetos sin preocuparse por ningún tipo de cambios de implementación de objetos / servicios utilizados, también si el mismo objeto que está utilizando será totalmente reemplazado (obviamente respetando la interfaz).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top