útil qué para inyección inyeccion explicacion ejemplo dependencias control dependency-injection

dependency injection - para - ¿Por qué se usa una inyección de dependencia?



inyeccion de dependencias spring (5)

Como indicaron las otras respuestas, la inyección de dependencia es una forma de crear sus dependencias fuera de la clase que lo usa. Los inyectas desde el exterior y tomas el control sobre su creación lejos del interior de tu clase. Esta es también la razón por la cual la inyección de dependencia es una realización del principio de Inversión de control (IoC).

IoC es el principio, donde DI es el patrón. La razón por la que podría "necesitar más de un registrador" nunca se cumple, según mi experiencia, pero la razón real es que realmente la necesita, cada vez que prueba algo. Un ejemplo:

Mi característica:

Cuando miro una oferta, quiero marcar que la miré automáticamente, para que no olvide hacerlo.

Podrías probar esto así:

[Test] public void ShouldUpdateTimeStamp { // Arrange var formdata = { . . . } // System under Test var weasel = new OfferWeasel(); // Act var offer = weasel.Create(formdata) // Assert offer.LastUpdated.Should().Be(new DateTime(2013,01,13,13,01,0,0)); }

Entonces, en algún lugar de OfferWeasel , crea un objeto de oferta como este:

public class OfferWeasel { public Offer Create(Formdata formdata) { var offer = new Offer(); offer.LastUpdated = DateTime.Now; return offer; } }

El problema aquí es que esta prueba probablemente siempre fallará, ya que la fecha que se está configurando diferirá de la fecha que se afirma, incluso si solo pone DateTime.Now en el código de la prueba, es posible que esté desactivado por un par de milisegundos. y por lo tanto siempre fallará. Una mejor solución ahora sería crear una interfaz para esto, que le permita controlar a qué hora se establecerá:

public interface IGotTheTime { DateTime Now {get;} } public class CannedTime : IGotTheTime { public DateTime Now {get; set;} } public class ActualTime : IGotTheTime { public DateTime Now {get { return DateTime.Now; }} } public class OfferWeasel { private readonly IGotTheTime _time; public OfferWeasel(IGotTheTime time) { _time = time; } public Offer Create(Formdata formdata) { var offer = new Offer(); offer.LastUpdated = _time.Now; return offer; } }

La interfaz es la abstracción. Una es la cosa REAL, y la otra te permite fingir un tiempo donde se necesita. La prueba se puede cambiar así:

[Test] public void ShouldUpdateTimeStamp { // Arrange var date = new DateTime(2013, 01, 13, 13, 01, 0, 0); var formdata = { . . . } var time = new CannedTime { Now = date }; // System under test var weasel= new OfferWeasel(time); // Act var offer = weasel.Create(formdata) // Assert offer.LastUpdated.Should().Be(date); }

Así, aplicó el principio de "inversión de control", al inyectar una dependencia (obtener la hora actual). La razón principal para hacer esto es para una prueba de unidad aislada más fácil, hay otras formas de hacerlo. Por ejemplo, una interfaz y una clase aquí no son necesarias, ya que en C # las funciones se pueden pasar como variables, por lo que en lugar de una interfaz, podría usar una función Func<DateTime> para lograr lo mismo. O, si adopta un enfoque dinámico, simplemente pasa cualquier objeto que tenga el método equivalente ( tipificación pato ) y no necesita ninguna interfaz.

Casi nunca necesitarás más de un registrador. No obstante, la inyección de dependencia es esencial para el código tipificado estáticamente como Java o C #.

Y ... También se debe tener en cuenta que un objeto solo puede cumplir adecuadamente su propósito en tiempo de ejecución, si todas sus dependencias están disponibles, por lo que no es muy útil configurar la inyección de propiedades. En mi opinión, todas las dependencias deben satisfacerse cuando se llama al constructor, por lo que la clave es ir con constructor-injection.

Espero que haya ayudado.

Estoy tratando de entender las inyecciones de dependencia (DI), y una vez más fallé. Simplemente parece tonto. Mi código nunca es un lío; Apenas escribo funciones e interfaces virtuales (aunque lo hago una vez en una luna azul) y toda mi configuración se serializa mágicamente en una clase usando json.net (a veces usando un serializador XML).

No entiendo muy bien qué problema soluciona. Parece una forma de decir: "hola. Cuando se ejecuta en esta función, devuelva un objeto de este tipo y use estos parámetros / datos".
Pero ... ¿por qué usaría eso alguna vez? Tenga en cuenta que nunca he necesitado usar un object también, pero entiendo para qué sirve.

¿Cuáles son algunas situaciones reales en la construcción de un sitio web o una aplicación de escritorio en la que uno usaría DI? Puedo encontrar casos fácilmente por qué alguien puede querer usar interfaces / funciones virtuales en un juego, pero es extremadamente raro (lo suficientemente raro como para no recordar una sola instancia) usar eso en un código que no sea de juego.


Creo que la respuesta clásica es crear una aplicación más desacoplada, que no tiene conocimiento de qué implementación se utilizará durante el tiempo de ejecución.

Por ejemplo, somos un proveedor central de pagos y trabajamos con muchos proveedores de pagos en todo el mundo. Sin embargo, cuando se realiza una solicitud, no tengo idea de a qué procesador de pagos voy a llamar. Podría programar una clase con una tonelada de cajas de interruptores, tales como:

class PaymentProcessor{ private String type; public PaymentProcessor(String type){ this.type = type; } public void authorize(){ if (type.equals(Consts.PAYPAL)){ // Do this; } else if(type.equals(Consts.OTHER_PROCESSOR)){ // Do that; } } }

Ahora imagine que ahora necesitará mantener todo este código en una sola clase porque no está desacoplado correctamente, puede imaginar que para cada nuevo procesador que admita, deberá crear un nuevo caso de conmutación if // para Sin embargo, cada método, esto solo se vuelve más complicado, al usar la inyección de dependencia (o inversión de control), como a veces se llama, lo que significa que quienquiera que controle la ejecución del programa es conocido solo en tiempo de ejecución, y no complicación, podría lograr algo. Muy limpio y fácil de mantener.

class PaypalProcessor implements PaymentProcessor{ public void authorize(){ // Do PayPal authorization } } class OtherProcessor implements PaymentProcessor{ public void authorize(){ // Do other processor authorization } } class PaymentFactory{ public static PaymentProcessor create(String type){ switch(type){ case Consts.PAYPAL; return new PaypalProcessor(); case Consts.OTHER_PROCESSOR; return new OtherProcessor(); } } } interface PaymentProcessor{ void authorize(); }

** El código no compilará, lo sé :)


Creo que muchas veces las personas se confunden acerca de la diferencia entre la inyección de dependencia y un marco de inyección de dependencia (o un contenedor, como suele llamarse).

La inyección de dependencia es un concepto muy simple. En lugar de este código:

public class A { private B b; public A() { this.b = new B(); // A *depends on* B } public void DoSomeStuff() { // Do something with B here } } public static void Main(string[] args) { A a = new A(); a.DoSomeStuff(); }

escribes código como este:

public class A { private B b; public A(B b) { // A now takes its dependencies as arguments this.b = b; // look ma, no "new"! } public void DoSomeStuff() { // Do something with B here } } public static void Main(string[] args) { B b = new B(); // B is constructed here instead A a = new A(b); a.DoSomeStuff(); }

Y eso es. Seriamente. Esto le da un montón de ventajas. Dos importantes son la capacidad de controlar la funcionalidad desde un lugar central (la función Main() ) en lugar de distribuirla a lo largo de su programa, y ​​la capacidad de probar cada clase más fácilmente de forma aislada (porque puede pasar simulacros u otros objetos falsos a su constructor en lugar de un valor real).

El inconveniente, por supuesto, es que ahora tiene una mega función que conoce todas las clases utilizadas por su programa. Eso es lo que pueden ayudar los marcos DI. Pero si tiene problemas para entender por qué este enfoque es valioso, recomiendo comenzar primero con la inyección manual de dependencia, para que pueda apreciar mejor lo que los distintos marcos pueden hacer por usted.


La razón principal para utilizar DI es que desea poner la responsabilidad del conocimiento de la implementación donde está el conocimiento. La idea de DI está muy en línea con la encapsulación y el diseño por interfaz. Si el extremo frontal pide algunos datos al extremo posterior, entonces no es importante para el extremo frontal cómo resuelve esa pregunta el extremo posterior. Eso depende del manejador de solicitudes.

Eso ya es común en OOP durante mucho tiempo. Muchas veces creando piezas de código como:

I_Dosomething x = new Impl_Dosomething();

El inconveniente es que la clase de implementación todavía está codificada, por lo tanto, tiene el extremo frontal del conocimiento que se utiliza. DI lleva el diseño de la interfaz un paso más allá, ya que lo único que necesita saber la interfaz es el conocimiento de la interfaz. Entre DYI y DI está el patrón de un localizador de servicios, porque el extremo frontal tiene que proporcionar una clave (presente en el registro del localizador de servicios) para que su solicitud se resuelva. Ejemplo de localizador de servicios:

I_Dosomething x = ServiceLocator.returnDoing(String pKey);

Ejemplo de DI:

I_Dosomething x = DIContainer.returnThat();

Uno de los requisitos de DI es que el contenedor debe poder averiguar qué clase es la implementación de qué interfaz. Por lo tanto, un contenedor DI requiere un diseño fuertemente tipificado y solo una implementación para cada interfaz al mismo tiempo. Si necesita más implementaciones de una interfaz al mismo tiempo (como una calculadora), necesita el localizador de servicios o el patrón de diseño de fábrica.

D (b) I: Inyección de dependencias y diseño por interfaz. Sin embargo, esta restricción no es un problema práctico muy grande. La ventaja de usar D (b) I es que sirve la comunicación entre el cliente y el proveedor. Una interfaz es una perspectiva sobre un objeto o un conjunto de comportamientos. Lo último es crucial aquí.

Prefiero la administración de contratos de servicio junto con D (b) I en la codificación. Deberían ir juntos. El uso de D (b) I como una solución técnica sin la administración organizativa de los contratos de servicios no es muy beneficioso desde mi punto de vista, porque la DI es solo una capa adicional de encapsulación. Pero cuando puede usarlo junto con la administración de la organización, realmente puede hacer uso del principio de organización D (b) I ofrece. Puede ayudarlo a largo plazo a estructurar la comunicación con el cliente y otros departamentos técnicos en temas como pruebas, control de versiones y el desarrollo de alternativas. Cuando tiene una interfaz implícita como en una clase codificada, entonces es mucho menos comunicable con el tiempo que cuando la hace explícita utilizando D (b) I. Todo se reduce a mantenimiento, que es con el tiempo y no a la vez. :-)


Primero, quiero explicar una suposición que hago para esta respuesta. No siempre es cierto, pero muy a menudo:

Las interfaces son adjetivos; las clases son sustantivos

(En realidad, hay interfaces que también son sustantivos, pero quiero generalizar aquí).

Así, por ejemplo, una interfaz puede ser algo como IDisposable , IEnumerable o IPrintable . Una clase es una implementación real de una o más de estas interfaces: List o Map pueden ser implementaciones de IEnumerable .

Para obtener el punto: a menudo sus clases dependen unos de otros. Por ejemplo, podría tener una clase de Database que acceda a su base de datos (¡ah, sorpresa! ;-)), pero también desea que esta clase realice el registro sobre el acceso a la base de datos. Supongamos que tiene otro Logger clase y, a continuación, la Database depende del Logger .

Hasta ahora tan bueno.

Puede modelar esta dependencia dentro de su clase de Database con la siguiente línea:

var logger = new Logger();

y todo está bien. Está bien hasta el día en que se dé cuenta de que necesita un montón de registradores: a veces desea iniciar sesión en la consola, a veces en el sistema de archivos, a veces usando TCP / IP y un servidor de registro remoto, y así sucesivamente ...

Y, por supuesto, NO desea cambiar todo su código (mientras tiene millones de ellos) y reemplazar todas las líneas.

var logger = new Logger();

por:

var logger = new TcpLogger();

En primer lugar, esto no es divertido. En segundo lugar, esto es propenso a errores. Tercero, este es un trabajo estúpido y repetitivo para un mono entrenado. Entonces, ¿Qué haces?

Obviamente, es una buena idea introducir una interfaz ICanLog (o similar) implementada por todos los distintos registradores. Así que el paso 1 en tu código es que lo haces:

ICanLog logger = new Logger();

Ahora la inferencia de tipos ya no cambia el tipo, siempre tiene una única interfaz con la que desarrollar. El siguiente paso es que no desea tener un new Logger() una y otra vez. Por lo tanto, pone la confiabilidad para crear nuevas instancias en una sola clase de fábrica central y obtiene un código como:

ICanLog logger = LoggerFactory.Create();

La propia fábrica decide qué tipo de registrador crear. Su código ya no le importa, y si desea cambiar el tipo de registrador que se está utilizando, cámbielo una vez : dentro de la fábrica.

Ahora, por supuesto, puede generalizar esta fábrica y hacer que funcione para cualquier tipo:

ICanLog logger = TypeFactory.Create<ICanLog>();

En algún lugar, este TypeFactory necesita datos de configuración que la clase real ejemplifique cuando se solicita un tipo de interfaz específico, por lo que necesita una asignación. Por supuesto, puede hacer esta asignación dentro de su código, pero luego un cambio de tipo significa recompilar. Pero también podría poner esta asignación dentro de un archivo XML, por ejemplo. Esto le permite cambiar la clase realmente utilizada incluso después del tiempo de compilación (!), Lo que significa dinámicamente, ¡sin recompilar!

Para darle un ejemplo útil para esto: piense en un software que no se registra normalmente, pero cuando su cliente llama y le pide ayuda porque tiene un problema, todo lo que le envía es un archivo de configuración XML actualizado, y ahora tiene registro habilitado, y su soporte puede usar los archivos de registro para ayudar a su cliente.

Y ahora, cuando reemplaza un poco los nombres, termina con una implementación simple de un Localizador de servicio , que es uno de los dos patrones de Inversión de control (ya que invierte el control sobre quién decide qué clase exacta instanciar).

Todo esto reduce las dependencias en su código, pero ahora todo su código tiene una dependencia del localizador central de servicio único.

La inyección de dependencia es ahora el siguiente paso en esta línea: simplemente deshágase de esta única dependencia del localizador de servicios: en lugar de que varias clases soliciten al localizador de servicios una implementación para una interfaz específica, usted, una vez más, revertirá el control sobre quién ejemplifica qué .

Con la inyección de dependencia, su clase de Database ahora tiene un constructor que requiere un parámetro de tipo ICanLog :

public Database(ICanLog logger) { ... }

Ahora su base de datos siempre tiene un registrador para usar, pero ya no sabe de dónde proviene este registrador.

Y aquí es donde entra en juego un marco DI: configura sus asignaciones una vez más y luego le pide a su marco DI que cree una instancia de su aplicación. Como la clase de Application requiere una implementación de ICanPersistData , se inyecta una instancia de la Database de Database , pero para eso primero debe crear una instancia del tipo de registrador que está configurado para ICanLog . Y así ...

Por lo tanto, para abreviar una larga historia: la inyección de dependencia es una de las dos formas de eliminar dependencias en su código. Es muy útil para los cambios de configuración después del tiempo de compilación, y es una gran cosa para la prueba de unidades (ya que hace que sea muy fácil inyectar talones y / o simulacros).

En la práctica, hay cosas que no puede hacer sin un localizador de servicios (por ejemplo, si no sabe de antemano cuántas instancias necesita una interfaz específica: un marco DI siempre inyecta solo una instancia por parámetro, pero puede llamar un localizador de servicios dentro de un bucle, por supuesto), por lo tanto, la mayoría de las veces, cada marco DI también proporciona un localizador de servicios.

Pero básicamente, eso es todo.

Espero que ayude.

PD: Lo que describí aquí es una técnica llamada inyección de constructor , también hay una inyección de propiedades en la que no se utilizan parámetros de constructores, pero las propiedades se utilizan para definir y resolver dependencias. Piense en la inyección de propiedades como una dependencia opcional, y en la inyección de constructores como dependencias obligatorias. Pero la discusión sobre esto está más allá del alcance de esta pregunta.