Inyección de dependencia - Dependency injection
En ingeniería de software , la inyección de dependencias es una técnica en la que un objeto recibe otros objetos de los que depende, llamados dependencias. Normalmente, el objeto receptor se llama cliente y el objeto pasado ('inyectado') se llama servicio . El código que pasa el servicio al cliente se llama inyector. En lugar de que el cliente especifique qué servicio utilizará, el inyector le dice al cliente qué servicio utilizar. La 'inyección' se refiere al paso de una dependencia (un servicio) al cliente que lo usa.
El servicio pasa a formar parte del estado del cliente . Pasar el servicio al cliente, en lugar de permitir que un cliente cree o encuentre el servicio , es el requisito fundamental del patrón.
La intención detrás de la inyección de dependencia es lograr la separación de preocupaciones de construcción y uso de objetos. Esto puede aumentar la legibilidad y la reutilización del código.
La inyección de dependencia es una forma de la técnica más amplia de inversión de control . Un cliente que quiera llamar a algunos servicios no debería tener que saber cómo construir esos servicios. En cambio, el cliente delega en un código externo (el inyector). El cliente no conoce el inyector. El inyector pasa los servicios, que pueden existir o ser construidos por el propio inyector, al cliente. Luego, el cliente utiliza los servicios.
Esto significa que el cliente no necesita saber sobre el inyector, cómo construir los servicios o incluso qué servicios está utilizando realmente. El cliente solo necesita conocer las interfaces de los servicios, porque estas definen cómo el cliente puede utilizar los servicios. Esto separa la responsabilidad de "uso" de la responsabilidad de "construcción".
Visión general
Inyección de dependencia para niños de cinco años
Cuando vas y sacas cosas del refrigerador por ti mismo, puedes causar problemas. Puede dejar la puerta abierta, puede conseguir algo que mamá o papá no quieren que usted tenga. Incluso podría estar buscando algo que ni siquiera tenemos o que ha caducado.
Lo que debería hacer es indicar una necesidad, "Necesito algo para beber con el almuerzo", y luego nos aseguraremos de que tenga algo cuando se siente a comer.
John Munsch, 28 de octubre de 2009.
La inyección de dependencia resuelve los siguientes problemas:
- ¿Cómo puede una clase ser independiente de cómo se crean los objetos de los que depende?
- ¿Cómo se puede especificar la forma en que se crean los objetos en archivos de configuración separados?
- ¿Cómo puede una aplicación admitir diferentes configuraciones?
La creación de objetos directamente dentro de la clase compromete a la clase a implementaciones particulares. Esto hace que sea difícil cambiar la instanciación en tiempo de ejecución, especialmente en lenguajes compilados donde cambiar los objetos subyacentes puede requerir volver a compilar el código fuente.
La inyección de dependencia separa la creación de dependencias de un cliente del comportamiento del cliente, lo que promueve programas poco acoplados y los principios de inversión de dependencia y responsabilidad única . Básicamente, la inyección de dependencias se basa en pasar parámetros a un método .
La inyección de dependencia es un ejemplo del concepto más general de inversión de control .
Un ejemplo de inversión de control sin inyección de dependencia es el patrón del método de plantilla , donde el polimorfismo se logra mediante subclases . La inyección de dependencia implementa la inversión del control a través de la composición y, a menudo, es similar al patrón de estrategia . Si bien el patrón de estrategia está destinado a dependencias que son intercambiables a lo largo de la vida útil de un objeto , en la inyección de dependencia puede ser que se utilice solo una instancia única de una dependencia. Esto todavía logra el polimorfismo, pero a través de la delegación y la composición .
La inyección de dependencias contrasta directamente con el patrón del localizador de servicios , que permite a los clientes conocer el sistema que utilizan para encontrar dependencias.
Roles
La inyección de dependencia involucra cuatro roles:
- los objetos de servicio que se utilizarán
- el objeto cliente , cuyo comportamiento depende de los servicios que utiliza
- las interfaces que definen cómo el cliente puede utilizar los servicios
- el inyector , que construye los servicios y los inyecta en el cliente
Como analogía,
- servicio: un automóvil eléctrico, de gasolina, híbrido o diésel
- cliente: un conductor que usa el automóvil de la misma manera independientemente del motor
- Interfaz: transmisión automática , que garantiza que el conductor no tenga que comprender los detalles de los cambios de marcha.
- inyector: el padre que compró el automóvil para el conductor y decidió de qué tipo
Cualquier objeto que pueda utilizarse puede considerarse un servicio . Cualquier objeto que utilice otros objetos puede considerarse un cliente . Los nombres se relacionan solo con el papel que juegan los objetos en una inyección.
Las interfaces son los tipos que el cliente espera que sean sus dependencias. El cliente no debe conocer la implementación específica de sus dependencias, solo conocer el nombre de la interfaz y la API . Como resultado, el cliente no necesitará cambiar incluso si cambia lo que está detrás de la interfaz. La inyección de dependencia puede funcionar con interfaces verdaderas o clases abstractas, pero también con servicios concretos , aunque esto violaría el principio de inversión de dependencia y sacrificaría el desacoplamiento dinámico que permite las pruebas . Solo se requiere que el cliente nunca trate sus interfaces como concretas construyéndolas o extendiéndolas. Si la interfaz se refactoriza de una clase a un tipo de interfaz (o viceversa), será necesario volver a compilar el cliente. Esto es significativo si el cliente y los servicios se publican por separado.
El inyector presenta servicios al cliente. A menudo, también construye al cliente. Un inyector puede conectar un gráfico de objeto complejo tratando el mismo objeto como cliente en un punto y como servicio en otro. El inyector en sí puede ser en realidad muchos objetos trabajando juntos, pero puede que no sea el cliente (ya que esto crearía una dependencia circular ). El inyector puede denominarse ensamblador, proveedor, contenedor, fábrica, constructor, resorte o código de construcción.
Como disciplina, la inyección de dependencia pide que todos los objetos separen la construcción y el comportamiento. Depender de un marco DI para la construcción puede llevar a prohibir la new
palabra clave o, de manera menos estricta, a permitir solo la construcción directa de objetos de valor .
Estructura
En el diagrama de clases de UML anterior , la Client
clase requiere ServiceA
y ServiceB
, pero no crea una instancia de los objetos ServiceA1
y ServiceB1
directamente.
En cambio, una Injector
clase crea los objetos y los inyecta en el Client
. El Client
es independiente de qué clases se instancian.
El diagrama de secuencia UML de la derecha muestra las interacciones en tiempo de ejecución:
- El
Injector
objeto crea los objetosServiceA1
yServiceB1
. - El
Injector
crea elClient
objeto. - El
Injector
inyecta los objetosServiceA1
yServiceB1
en elClient
objeto.
Ventajas y desventajas
Ventajas
Un beneficio básico de la inyección de dependencias es un menor acoplamiento entre clases y sus dependencias. Al eliminar el conocimiento de un cliente de cómo se implementan sus dependencias, los programas se vuelven más reutilizables, probables y fáciles de mantener.
Esto también da como resultado una mayor flexibilidad: un cliente puede actuar sobre cualquier cosa que admita la interfaz intrínseca que espera el cliente.
Muchos de los beneficios de la inyección de dependencia son particularmente relevantes para las pruebas unitarias .
Por ejemplo, la inyección de dependencia se puede utilizar para externalizar los detalles de configuración de un sistema en archivos de configuración, lo que permite que el sistema se reconfigure sin volver a compilarlo. Se pueden escribir configuraciones separadas para diferentes situaciones que requieren diferentes implementaciones de componentes. Esto incluye pruebas. De manera similar, debido a que la inyección de dependencias no requiere ningún cambio en el comportamiento del código, se puede aplicar al código heredado como refactorización . El resultado son clientes que son más independientes y que son más fáciles de probar unitariamente de forma aislada utilizando stubs u objetos simulados que simulan otros objetos que no están bajo prueba. Esta facilidad de prueba es a menudo el primer beneficio que se nota cuando se usa la inyección de dependencia.
De manera más general, la inyección de dependencias reduce el código repetitivo , ya que toda la creación de dependencias es manejada por un componente singular.
Finalmente, la inyección de dependencia permite el desarrollo concurrente. Dos desarrolladores pueden desarrollar clases de forma independiente que se utilicen entre sí, mientras que solo necesitan conocer la interfaz a través de la cual se comunicarán las clases. Los complementos a menudo son desarrollados por tiendas de terceros que ni siquiera hablan con los desarrolladores que crearon el producto que utiliza los complementos.
Desventajas
Las críticas a la inyección de dependencia argumentan que:
- Crea clientes que exigen detalles de configuración, que pueden ser onerosos cuando hay disponibles valores predeterminados obvios.
- Haga que el código sea difícil de rastrear porque separa el comportamiento de la construcción.
- Suele implementarse con reflexión o programación dinámica. Esto puede dificultar la automatización de IDE .
- Por lo general, requiere un mayor esfuerzo de desarrollo inicial.
- Fuerza la complejidad fuera de las clases y en los vínculos entre clases que pueden ser más difíciles de administrar.
- Fomentar la dependencia de un marco.
Tipos de inyección de dependencia
Hay al menos tres formas en que un cliente puede recibir una referencia a un módulo externo:
- Inyección de constructor: las dependencias se proporcionan a través del constructor de clases de un cliente.
- Inyección de setter: el cliente expone un método de setter que el inyector usa para inyectar la dependencia.
- Inyección de interfaz: la interfaz de la dependencia proporciona un método de inyección que inyectará la dependencia en cualquier cliente que se le pase.
Los marcos de DI y los marcos de prueba pueden usar otros tipos de inyección.
Algunos marcos de prueba modernos ni siquiera requieren que los clientes acepten activamente la inyección de dependencias, lo que hace que el código heredado sea comprobable. En Java , la reflexión puede hacer públicos los atributos privados al realizar pruebas y, por lo tanto, aceptar inyecciones por asignación.
Algunos intentos de inversión de control simplemente sustituyen una forma de dependencia por otra. Como regla general, si un programador no puede mirar nada más que el código del cliente y decir qué marco se está utilizando, entonces el cliente tiene una dependencia codificada en el marco.
Sin inyección de dependencia
En el siguiente ejemplo de Java , la Client
clase contiene una Service
variable miembro inicializada en el constructor . El cliente controla qué servicio se utiliza y su construcción. El cliente tiene una dependencia codificada de forma rígida en ExampleService
.
public class Client {
// Internal reference to the service used by this client
private ExampleService service;
// Constructor
Client() {
// Specify a specific implementation instead of using dependency injection
service = new ExampleService();
}
// Method that uses the services
public String greet() {
return "Hello " + service.getName();
}
}
Podemos ajustar este ejemplo utilizando las técnicas que se describen a continuación.
Inyección de constructor
Este método requiere que el cliente proporcione un parámetro en un constructor para la dependencia. Esto asegura que el objeto del cliente esté siempre en un estado válido, en lugar de que algunas de sus dependencias sean nulas o no se establezcan. Este puede ser un primer paso para hacer que el cliente sea inmutable y, por lo tanto, seguro para subprocesos . Sin embargo, por sí solo, este patrón carece de la flexibilidad para cambiar sus dependencias más adelante.
// Constructor
Client(Service service, Service otherService) {
if (service == null) {
throw new InvalidParameterException("service must not be null");
}
if (otherService == null) {
throw new InvalidParameterException("otherService must not be null");
}
// Save the service references inside this client
this.service = service;
this.otherService = otherService;
}
Inyección de setter
Este método requiere que el cliente proporcione un método de establecimiento para la dependencia. Los inyectores pueden manipular las referencias de dependencia en cualquier momento.
Esto ofrece flexibilidad, pero es difícil garantizar que todas las dependencias se inyecten antes de que se utilice el cliente. Debido a que estas inyecciones ocurren de forma independiente, una dependencia puede dejarse nula simplemente porque el inyector no llama a su establecedor. Por el contrario, una dependencia declarada en un constructor significa que no se puede construir un objeto a menos que se satisfaga la dependencia.
El siguiente ejemplo muestra una forma para que un cliente verifique que la inyección se completó cuando se usó.
// Set the service to be used by this client
public void setService(Service service) {
this.service = service;
}
// Set the other service to be used by this client
public void setOtherService(Service otherService) {
this.otherService = otherService;
}
// Check the service references of this client
private void validateState() {
if (service == null) {
throw new IllegalStateException("service must not be null");
}
if (otherService == null) {
throw new IllegalStateException("otherService must not be null");
}
}
// Method that uses the service references
public void doSomething() {
validateState();
service.doYourThing();
otherService.doYourThing();
}
Inyección de interfaz
Con la inyección de interfaz, las dependencias pueden ignorar por completo a sus clientes, y aun así enviar y recibir referencias a nuevos clientes.
De esta forma, las dependencias se convierten en inyectores. La clave es que el método de inyección (que podría ser simplemente un método de establecimiento) se proporciona a través de una interfaz.
Todavía se necesita un ensamblador para presentar el cliente y sus dependencias. El ensamblador toma una referencia al cliente, la envía a la interfaz de establecimiento que establece esa dependencia y la pasa a ese objeto de dependencia que, a su vez, pasa una referencia a sí mismo al cliente.
Para que la inyección de interfaz tenga valor, la dependencia debe hacer algo además de simplemente devolverse una referencia a sí misma. Esto podría actuar como una fábrica o un sub-ensamblador para resolver otras dependencias, abstrayendo así algunos detalles del ensamblador principal. Podría ser un recuento de referencias para que la dependencia sepa cuántos clientes lo están usando. Si la dependencia mantiene una colección de clientes, luego podría inyectarlos a todos con una instancia diferente de sí misma.
// Service setter interface.
public interface ServiceSetter {
public void setService(Service service);
}
// Client class
public class Client implements ServiceSetter {
// Internal reference to the service used by this client.
private Service service;
// Set the service that this client is to use.
@Override
public void setService(Service service) {
this.service = service;
}
}
// Injector class
public class ServiceInjector {
Set<ServiceSetter> clients;
public void inject(ServiceSetter client) {
clients.add(client);
client.setService(new ServiceFoo());
}
public void switchToBar() {
for (Client client : clients) {
client.setService(new ServiceBar());
}
}
}
// Service classes
public class ServiceFoo implements Service {}
public class ServiceBar implements Service {}
Montaje
La forma más sencilla de implementar la inyección de dependencias es organizar manualmente los servicios y los clientes, normalmente en la "raíz" del programa, donde comienza la ejecución.
public class Injector {
public static void main(String[] args) {
// Build the dependencies first
Service service = new ExampleService();
// Inject the service, constructor style
Client client = new Client(service);
// Use the objects
System.out.println(client.greet());
}
}
El ejemplo anterior construye el gráfico de objetos manualmente y luego lo invoca. Este inyector no es 'puro', ya que usa uno de los objetos que construye ( Client
).
La construcción manual puede ser más compleja e involucrar a constructores , fábricas u otros patrones de construcción .
Frameworks
La inyección manual de dependencias se convierte en un marco de inyección de dependencias una vez que el código de construcción ya no está personalizado para la aplicación y, en cambio, es universal.
Los marcos de aplicación como Weld , Spring , Guice , Play framework , Salta , Glassfish HK2 , Dagger y Managed Extensibility Framework admiten la inyección de dependencia, pero no es necesario que lo haga.
Los marcos como Spring pueden construir objetos y conectarlos antes de devolver una referencia al cliente. Debido a que los marcos como Spring permiten que los detalles del ensamblaje se externalicen en los archivos de configuración, todas las menciones del concreto ExampleService
se pueden mover del código a los datos de configuración:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Injector {
public static void main(String[] args) {
// -- Assembling objects -- //
BeanFactory beanfactory = new ClassPathXmlApplicationContext("Beans.xml");
Client client = (Client) beanfactory.getBean("client");
// -- Using objects -- //
System.out.println(client.greet());
}
}
Incluso con un gráfico de objetos largo y complejo, la única clase mencionada en el código es el punto de entrada, en este caso Client
.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="service" class="ExampleService">
</bean>
<bean id="client" class="Client">
<constructor-arg value="service" />
</bean>
</beans>
Client
y Service
no han sufrido ningún cambio para trabajar con Spring y siguen siendo POJO . Spring puede conectar servicios y clientes que desconocen por completo su existencia. Al evitar que las anotaciones y llamadas específicas de Spring se extiendan entre muchas clases, el sistema depende solo ligeramente de Spring.
Mantener los POJO puros requiere esfuerzo. En lugar de mantener archivos de configuración complejos, las clases pueden usar anotaciones para permitir que Spring haga el trabajo duro usando la convención sobre la configuración .
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Injector {
public static void main(String[] args) {
// Assemble the objects
BeanFactory beanfactory = new AnnotationConfigApplicationContext(MyConfiguration.class);
Client client = beanfactory.getBean(Client.class);
// Use the objects
System.out.println(client.greet());
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan
public class MyConfiguration {
@Bean
public Client client(ExampleService service) {
return new Client(service);
}
}
@Component
public class ExampleService {
public String getName() {
return "World!";
}
}
Los diferentes inyectores (fábricas, localizadores de servicios y contenedores de inyección de dependencia) se diferencian principalmente en el lugar donde se pueden usar. Mover llamadas a una fábrica o un localizador de servicios fuera del cliente y dentro de la raíz del programa es equivalente a usar un contenedor de inyección de dependencia.
Al eliminar el conocimiento del inyector, el cliente se libera del conocimiento del mundo exterior, se queda atrás. Sin embargo, cualquier objeto que utilice otros objetos puede considerarse un cliente, incluido el objeto que contiene la raíz del programa. Como resultado, main
en el ejemplo anterior se está utilizando realmente el patrón de localizador de servicios. Esto no se puede evitar porque la elección de las implementaciones del servicio debe realizarse en algún lugar.
Ejemplos de
AngularJS
En AngularJS , solo hay tres formas en que un componente (objeto o función) puede acceder directamente a sus dependencias:
- El componente puede crear la dependencia, normalmente utilizando el
new
operador. - El componente puede buscar la dependencia, haciendo referencia a una variable global.
- Se puede pasar la dependencia al componente donde sea necesario.
Las dos primeras opciones no son óptimas porque codifican de forma rígida la dependencia del componente. Esto es problemático en las pruebas , donde a menudo es deseable simular dependencias para el aislamiento de la prueba.
La tercera opción elimina la responsabilidad de localizar la dependencia del componente.
function SomeClass(greeter) {
this.greeter = greeter;
}
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
SomeClass
simplemente se entrega al recibidor cuando se crea una instancia. Esto le da la responsabilidad de la construcción de dependencias al código que construye SomeClass
.
Para gestionar esto, cada aplicación AngularJS tiene un 'inyector': un localizador de servicios responsable de la construcción y búsqueda de dependencias.
// Provide the wiring information in a module
var myModule = angular.module('myModule', []);
// Teach the injector how to build a greeter service.
// greeter is dependent on the $window service.
// The greeter service is an object that
// contains a greet method.
myModule.factory('greeter', function($window) {
return {
greet: function(text) {
$window.alert(text);
}
};
});
Cree un nuevo inyector que pueda proporcionar componentes definidos en el myModule
módulo y solicite nuestro servicio de bienvenida al inyector.
var injector = angular.injector(['myModule', 'ng']);
var greeter = injector.get('greeter');
Solicitar dependencias resuelve el problema de la codificación rígida, pero también significa que el inyector debe pasarse por toda la aplicación. Pasar el inyector infringe la Ley de Deméter . Para remediar esto, usamos una notación declarativa en nuestras plantillas HTML, para pasar la responsabilidad de crear componentes al inyector:
<div ng-controller="MyController">
<button ng-click="sayHello()">Hello</button>
</div>
function MyController($scope, greeter) {
$scope.sayHello = function() {
greeter.greet('Hello World');
};
}
Cuando AngularJS compila el HTML, procesa la ng-controller
directiva, que a su vez le pide al inyector que cree una instancia del controlador y sus dependencias.
injector.instantiate(MyController);
Debido a que ng-controller
difiere que el inyector cree una instancia de la clase, puede satisfacer las dependencias de MyController
sin que el controlador sepa sobre el inyector. El código de la aplicación simplemente declara las dependencias que necesita, preservando la Ley de Demeter .
C#
Ejemplo de inyección de constructor , inyección de Setter e inyección de interfaz en C #
using System;
namespace DependencyInjection
{
// An interface for the library
interface IGamepadFunctionality
{
String GetGamepadName();
void SetVibrationPower(float InPower);
}
// Concrete implementation of the xbox controller functionality
class XBoxGamepad : IGamepadFunctionality
{
readonly String GamepadName = "XBox Controller";
float VibrationPower = 1.0f;
public String GetGamepadName() => GamepadName;
public void SetVibrationPower(float InPower) => VibrationPower = Math.Clamp(InPower, 0.0f, 1.0f);
}
// Concrete implementation of the playstation controller functionality
class PlaystationJoystick : IGamepadFunctionality
{
readonly String ControllerName = "Playstation controller";
float VibratingPower = 100.0f;
public String GetGamepadName() => ControllerName;
public void SetVibrationPower(float InPower) => VibratingPower = Math.Clamp(InPower * 100.0f, 0.0f, 100.0f);
}
// Concrete implementation of the steam controller functionality
class SteamController : IGamepadFunctionality
{
readonly String JoystickName = "Steam controller";
double Vibrating = 1.0;
public String GetGamepadName() => JoystickName;
public void SetVibrationPower(float InPower) => Vibrating = Convert.ToDouble(Math.Clamp(InPower, 0.0f, 1.0f));
}
// An interface for gamepad functionality injections
interface IGamepadFunctionalityInjector
{
void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality);
}
class CGamepad : IGamepadFunctionalityInjector
{
IGamepadFunctionality _GamepadFunctionality;
public CGamepad()
{
}
// Constructor injection
public CGamepad(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
// Setter injection
public void SetGamepadFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
// Interface injection
public void InjectFunctionality(IGamepadFunctionality InGamepadFunctionality) => _GamepadFunctionality = InGamepadFunctionality;
public void Showcase()
{
String Message = String.Format("We're using the {0} right now, do you want to change the vibrating power?\r\n", _GamepadFunctionality.GetGamepadName());
Console.WriteLine(Message);
}
}
enum EPlatforms: byte
{
Xbox,
Playstation,
Steam
}
class CGameEngine
{
EPlatforms _Platform;
CGamepad _Gamepad;
public void SetPlatform(EPlatforms InPlatform)
{
_Platform = InPlatform;
switch(_Platform)
{
case EPlatforms.Xbox:
// injects dependency on XBoxGamepad class through Constructor Injection
_Gamepad = new CGamepad(new XBoxGamepad());
break;
case EPlatforms.Playstation:
_Gamepad = new CGamepad();
// injects dependency on PlaystationJoystick class through Setter Injection
_Gamepad.SetGamepadFunctionality(new PlaystationJoystick());
break;
case EPlatforms.Steam:
_Gamepad = new CGamepad();
// injects dependency on SteamController class through Interface Injection
_Gamepad.InjectFunctionality(new SteamController());
break;
}
_Gamepad.Showcase();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
CGameEngine Engine = new CGameEngine();
Engine.SetPlatform(EPlatforms.Steam);
Engine.SetPlatform(EPlatforms.Xbox);
Engine.SetPlatform(EPlatforms.Playstation);
}
}
}
Ver también
- Lenguaje de descripción de arquitectura
- Patrón de fábrica
- Inversión de control
- Plug-in (informática)
- Patrón de estrategia
- AngularJS
- Patrón de localizador de servicios
- Parámetro (programación informática)
- Quaject
Referencias
enlaces externos
- Raíz de composición por Mark Seemann
- Una guía para principiantes sobre la inyección de dependencia
- Inyección de dependencias y objetos comprobables: diseño de objetos comprobables y poco acoplados - Jeremy Weiskotten; Dr. Dobb's Journal , mayo de 2006.
- Patrones de diseño: inyección de dependencia - MSDN Magazine, septiembre de 2005
- El artículo original de Martin Fowler que introdujo el término inyección de dependencia
- P de EAA: complemento
- La rica herencia de ingeniería detrás de la inyección de dependencia - Andrew McVeigh - Una historia detallada de la inyección de dependencia.
- ¿Qué es la inyección de dependencia? - Una explicación alternativa - Jakob Jenkov
- Escribir código más comprobable con inyección de dependencia - Developer.com, octubre de 2006
- Descripción general del marco de extensibilidad administrado - MSDN
- Descripción anticuada del mecanismo de dependencia por Hunt 1998
- Refactorice su camino hacia un contenedor de inyección de dependencia
- Entendiendo DI en PHP
- No necesita un contenedor de inyección de dependencia