stringtranslate.com

Inyección de dependencia

Un diagrama de un contenedor de inyección de dependencia arquetípico para la plataforma .NET.
La inyección de dependencia se utiliza a menudo junto con marcos especializados, conocidos como "contenedores", para facilitar la composición de programas.

En ingeniería de software , la inyección de dependencias es una técnica de programación en la que un objeto o función recibe otros objetos o funciones que necesita, en lugar de crearlos internamente. La inyección de dependencias tiene como objetivo separar las preocupaciones de construir objetos y usarlos, lo que lleva a programas débilmente acoplados . [1] [2] [3] El patrón garantiza que un objeto o función que desea utilizar un servicio determinado no debería tener que saber cómo construir esos servicios. En cambio, el " cliente " receptor (objeto o función) recibe sus dependencias mediante un código externo (un "inyector"), del que no es consciente. [4] La inyección de dependencias hace explícitas las dependencias implícitas y ayuda a resolver los siguientes problemas: [5]

La inyección de dependencia se utiliza a menudo para mantener el código en línea con el principio de inversión de dependencia . [6] [7]

En lenguajes tipados estáticamente, el uso de inyección de dependencia significa que un cliente solo necesita declarar las interfaces de los servicios que utiliza, en lugar de sus implementaciones concretas, lo que hace más fácil cambiar los servicios que se usan en tiempo de ejecución sin tener que volver a compilar.

Los marcos de aplicación suelen combinar la inyección de dependencias con la inversión de control . En la inversión de control, el marco primero construye un objeto (como un controlador) y luego le pasa el flujo de control . Con la inyección de dependencias, el marco también instancia las dependencias declaradas por el objeto de aplicación (a menudo en los parámetros del método constructor) y pasa las dependencias al objeto. [8]

La inyección de dependencias implementa la idea de "invertir el control sobre las implementaciones de dependencias", por lo que ciertos marcos de Java nombran genéricamente el concepto "inversión de control" (que no debe confundirse con inversión del flujo de control ). [9]

Roles

Inyección de dependencia para niños de cinco años

Cuando vas a buscar cosas del refrigerador para ti, puedes causar problemas. Podrías dejar la puerta abierta, podrías encontrar algo que mamá o papá no quieren que tengas. Incluso podrías estar buscando algo que ni siquiera tenemos o que está vencido.

Lo que debes hacer es expresar una necesidad: "Necesito algo para beber con el almuerzo", y luego nos aseguraremos de que tengas algo cuando te sientes a comer algo.

John Munsch, 28 de octubre de 2009. [2] [10] [11]

La inyección de dependencia involucra cuatro roles: servicios, clientes, interfaces e inyectores.

Servicios y clientes

Un servicio es cualquier clase que contiene una funcionalidad útil. A su vez, un cliente es cualquier clase que utiliza servicios. Los servicios que requiere un cliente son las dependencias del cliente .

Cualquier objeto puede ser un servicio o un cliente; los nombres se relacionan únicamente con el papel que desempeñan los objetos en una inyección. El mismo objeto puede incluso ser tanto un cliente (utiliza servicios inyectados) como un servicio (se inyecta en otros objetos). Tras la inyección, el servicio pasa a formar parte del estado del cliente y está disponible para su uso. [12]

Interfaces

Los clientes no deberían saber cómo se implementan sus dependencias, solo sus nombres y API . Un servicio que recupera correos electrónicos , por ejemplo, puede usar los protocolos IMAP o POP3 en segundo plano, pero es probable que este detalle sea irrelevante para el código de llamada que simplemente desea recuperar un correo electrónico. Al ignorar los detalles de implementación, los clientes no necesitan cambiar cuando lo hacen sus dependencias.

Inyectores

El inyector , a veces también llamado ensamblador, contenedor, proveedor o fábrica, introduce servicios al cliente.

La función de los inyectores es construir y conectar gráficos de objetos complejos, donde los objetos pueden ser tanto clientes como servicios. El propio inyector puede ser muchos objetos que trabajan juntos, pero no debe ser el cliente, ya que esto crearía una dependencia circular .

Debido a que la inyección de dependencias separa cómo se construyen los objetos de cómo se utilizan, a menudo disminuye la importancia de la newpalabra clave que se encuentra en la mayoría de los lenguajes orientados a objetos . Debido a que el marco se encarga de la creación de servicios, el programador tiende a construir directamente solo objetos de valor que representan entidades en el dominio del programa (como un Employeeobjeto en una aplicación empresarial o un Orderobjeto en una aplicación de compras). [13] [14] [15] [16]

Analogía

Como analogía, los automóviles pueden considerarse servicios que realizan la útil tarea de transportar personas de un lugar a otro. Los motores de los automóviles pueden requerir gasolina , diésel o electricidad , pero este detalle no es importante para el cliente (el conductor), a quien solo le importa si puede llegar a su destino.

Los coches presentan una interfaz uniforme a través de sus pedales, volantes y otros controles. Por lo tanto, ya no importa con qué motor se les haya "inyectado" en la línea de producción y los conductores pueden cambiar de coche según sus necesidades.

Ventajas y desventajas

Ventajas

Un beneficio básico de la inyección de dependencia es la disminución del acoplamiento entre las clases y sus dependencias. [17] [18]

Al eliminar el conocimiento del cliente sobre cómo se implementan sus dependencias, los programas se vuelven más reutilizables, comprobables y mantenibles. [19]

Esto también da como resultado una mayor flexibilidad: un cliente puede actuar sobre cualquier cosa que admita la interfaz intrínseca que el cliente espera. [20]

De manera más general, la inyección de dependencia reduce el código repetitivo , ya que toda la creación de dependencia es manejada por un componente singular. [19]

Por último, la inyección de dependencias permite el desarrollo concurrente. Dos desarrolladores pueden desarrollar de forma independiente clases que se utilicen entre sí, y solo necesitan conocer la interfaz a través de la cual se comunicarán las clases. Los complementos suelen ser desarrollados por terceros que nunca se comunican con los desarrolladores del producto original. [21]

Pruebas

Muchos de los beneficios de la inyección de dependencia son particularmente relevantes para las pruebas unitarias .

Por ejemplo, la inyección de dependencias se puede utilizar para externalizar los detalles de configuración de un sistema en archivos de configuración, lo que permite reconfigurar el sistema sin tener que volver a compilarlo. Se pueden escribir configuraciones independientes para distintas situaciones que requieran distintas implementaciones de componentes. [22]

De manera similar, debido a que la inyección de dependencia no requiere ningún cambio en el comportamiento del código, se puede aplicar al código heredado como una refactorización . Esto hace que los clientes sean más independientes y sea más fácil realizar pruebas unitarias 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 al utilizar la inyección de dependencia. [23]

Desventajas

Los críticos de la inyección de dependencia argumentan que:

Tipos de inyección de dependencia

Hay tres formas principales en las que un cliente puede recibir servicios inyectados: [29]

En algunos marcos, los clientes no necesitan aceptar activamente la inyección de dependencias. En Java , por ejemplo, la reflexión puede hacer públicos los atributos privados al probar e inyectar servicios directamente. [30]

Sin inyección de dependencia

En el siguiente ejemplo de Java , la Clientclase contiene una Service variable miembro inicializada en el constructor . El cliente construye y controla directamente qué servicio utiliza, creando una dependencia codificada.

clase pública Cliente { servicio privado servicio ;       Cliente () { // La dependencia está codificada. this . service = new ExampleService (); } }       

Inyección de constructor

La forma más común de inyección de dependencias es que una clase solicite sus dependencias a través de su constructor . Esto garantiza que el cliente siempre esté en un estado válido, ya que no se puede crear una instancia sin sus dependencias necesarias.

clase pública Cliente { servicio privado servicio ;       // La dependencia se inyecta a través de un constructor. Cliente ( Servicio servicio ) { if ( servicio == null ) { throw new IllegalArgumentException ( "el servicio no debe ser nulo" ); } this . servicio = servicio ; } }                

Inyección de setter

Al aceptar dependencias a través de un método de establecimiento , en lugar de un constructor, los clientes pueden permitir que los inyectores manipulen sus dependencias en cualquier momento. Esto ofrece flexibilidad, pero dificulta garantizar que todas las dependencias se inyecten y sean válidas antes de que se use el cliente.

clase pública Cliente { servicio privado servicio ;       // La dependencia se inyecta a través de un método setter. public void setService ( Service service ) { if ( service == null ) { throw new IllegalArgumentException ( " el servicio no debe ser nulo" ); } this.service = service ; } }                  

Inyección de interfaz

Con la inyección de interfaz, las dependencias ignoran completamente a sus clientes, pero aún así envían y reciben referencias a nuevos clientes.

De esta manera, las dependencias se convierten en inyectores. La clave es que el método de inyección se proporciona a través de una interfaz.

Aún se necesita un ensamblador para presentar al cliente y sus dependencias. El ensamblador toma una referencia al cliente, la convierte en la interfaz de configuración 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 pasar una referencia a sí misma. Esto podría ser actuar como una fábrica o un subensamblador para resolver otras dependencias, abstrayendo así algunos detalles del ensamblador principal. Podría ser un conteo de referencias para que la dependencia sepa cuántos clientes la están utilizando. Si la dependencia mantiene una colección de clientes, más tarde podría inyectarles a todos una instancia diferente de sí misma.

Interfaz pública ServiceSetter { void setService ( Service service ); }      clase pública Cliente implementa ServiceSetter { servicio privado ;         @Override public void setService ( Service service ) { if ( service == null ) { throw new IllegalArgumentException ( " el servicio no debe ser nulo" ) ; } this.service = service ; } }                  clase pública ServiceInjector { privada final Set < ServiceSetter > clientes = nuevo HashSet <> ();         public void inject ( ServiceSetter cliente ) { this.clientes.add ( cliente ) ; cliente.setService ( new ExampleService ( ) ) ; }     public void switch ( ) { for ( Cliente cliente : this.clientes ) { cliente.setService ( new OtroEjemploServicio ( ) ) ; } } }         La clase pública ExampleService implementa Service {}     La clase pública AnotherExampleService implementa el servicio {}     

Asamblea

La forma más sencilla de implementar la inyección de dependencia es organizar manualmente los servicios y clientes, lo que normalmente se hace en la raíz del programa, donde comienza la ejecución.

clase pública Programa {    public static void main ( String [] args ) { // Construye el servicio. Servicio service = new ExampleService ( );            // Inyectar el servicio en el cliente. Cliente cliente = new Cliente ( servicio ) ;      // Utilice los objetos. System . out . println ( client . greeting ()); } }  

La construcción manual puede ser más compleja e involucrar constructores , fábricas u otros patrones de construcción .

Marcos

Un diagrama de clases de contenedores de inyección de dependencia en .NET Framework.
Los contenedores como Ninject o StructureMap se utilizan comúnmente en lenguajes de programación orientados a objetos para lograr la inyección de dependencia y la inversión de control .

La inyección manual de dependencias suele ser tediosa y propensa a errores en proyectos de gran envergadura, por lo que se promueve el uso de marcos que automatizan el proceso. 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 es personalizado para la aplicación y, en cambio, es universal. [31] Si bien son útiles, estas herramientas no son necesarias para realizar la inyección de dependencias. [32] [33]

Algunos marcos, como Spring , pueden usar archivos de configuración externos para planificar la composición del programa:

importar org.springframework.beans.factory.BeanFactory ; importar org.springframework.context.ApplicationContext ; importar org.springframework.context.support.ClassPathXmlApplicationContext ;   clase pública Inyector {   public static void main ( String [] args ) { // Los detalles sobre qué servicio concreto utilizar se almacenan en una configuración separada del programa en sí. BeanFactory beanfactory = new ClassPathXmlApplicationContext ( "Beans.xml" ); Client client = ( Client ) beanfactory . getBean ( "client" ); System . out . println ( client . greeting ()); } }             

Incluso con un gráfico de objetos potencialmente largo y complejo, la única clase mencionada en el código es el punto de entrada, en este caso Client. Clientno ha sufrido ningún cambio para trabajar con Spring y sigue siendo un POJO . [34] [35] [36] Al evitar que las anotaciones y llamadas específicas de Spring se distribuyan entre muchas clases, el sistema sigue dependiendo solo vagamente de Spring. [27]

Ejemplos

AngularJS

El siguiente ejemplo muestra un componente AngularJS que recibe un servicio de saludo a través de la inyección de dependencia.

función SomeClass ( greeter ) { this.greeter = greeter ; }     SomeClass . prototipo . hacerAlgo = función ( nombre ) { this . saludo . saludo ( nombre ); }    

Cada aplicación AngularJS contiene un localizador de servicios responsable de la construcción y búsqueda de dependencias.

// Proporcionar la información de cableado en un módulo var myModule = angular . module ( 'myModule' , []);    // Enseñe al inyector cómo crear un servicio de saludo. // El servicio de saludo depende del servicio $window. myModule . factory ( 'greeter' , function ( $window ) { return { greeting : function ( text ) { $window . alert ( text ); } }; });          

Luego podemos crear un nuevo inyector que proporcione los componentes definidos en el myModulemódulo, incluido el servicio de recepción.

var injector = angular . injector ([ 'miMódulo' , 'ng' ]); var saludo = injector . get ( 'saludo' );       

Para evitar el antipatrón del localizador de servicios , AngularJS permite la notación declarativa en plantillas HTML que delega la creación de componentes al inyector.

< div  ng-controller = "MyController" >  < botón  ng-click = "sayHello()" > Hola </ botón > </ div >
función MyController ( $scope , greeter ) { $ scope.sayHello = function () { greeter.greeter ( ' Hola mundo' ) ; } ; }         

La ng-controllerdirectiva activa el inyector para crear una instancia del controlador y sus dependencias.

DO#

Este ejemplo proporciona un ejemplo de inyección de constructor en C# .

usando Sistema ; espacio de nombres DependencyInjection ; // Nuestro cliente solo conocerá esta interfaz, no qué gamepad específico está usando. interface IGamepadFunctionality { string GetGamepadName (); void SetVibrationPower ( float power ); }       // Los siguientes servicios proporcionan implementaciones concretas de la interfaz anterior.clase XBoxGamepad : IGamepadFunctionality { float vibratorPower = 1.0f ; public string GetGamepadName () => " Mando Xbox " ; public void SetVibrationPower ( float power ) = > this.vibrationPower = Math.Clamp ( power , 0.0f , 1.0f ) ; }                         clase PlaystationJoystick : IGamepadFunctionality { float vibratingPower = 100.0f ; public string GetGamepadName () => "Mando de PlayStation" ; public void SetVibrationPower ( float power ) => this . vibratingPower = Math . Clamp ( power * 100.0f , 0.0f , 100.0f ); }                           clase SteamController : IGamepadFunctionality { double vibrating = 1.0 ; public string GetGamepadName () => " Mando de Steam " ; public void SetVibrationPower ( float power ) = > this.vibrating = Convert.ToDouble ( Math.Clamp ( power , 0.0f , 1.0f ) ) ; }                         // Esta clase es el cliente que recibe un servicio. class Gamepad { IGamepadFunctionality gamepadFunctionality ;     // El servicio se inyecta a través del constructor y se almacena en el campo anterior. public Gamepad ( IGamepadFunctionality gamepadFunctionality ) => this . gamepadFunctionality = gamepadFunctionality ;        public void Showcase () { // Se utiliza el servicio inyectado. var gamepadName = this . gamepadFunctionality . GetGamepadName (); var message = $"Estamos usando el {gamepadName} en este momento, ¿quieres cambiar la potencia de vibración?" ; Console . WriteLine ( message ); } }              clase Program { static void Main () { var steamController = new SteamController (); // También podríamos haber pasado un XboxController, PlaystationJoystick, etc. // El gamepad no sabe lo que está usando y no lo necesita. var gamepad = new Gamepad ( steamController ); gamepad . Showcase (); } }                      

Ir

Go no admite clases y, por lo general, la inyección de dependencias se abstrae mediante una biblioteca dedicada que utiliza reflexión o genéricos (estos últimos se admiten desde Go 1.18 [37] ). [38] Un ejemplo más simple sin utilizar bibliotecas de inyección de dependencias se ilustra con el siguiente ejemplo de una aplicación web MVC .

Primero, pase las dependencias necesarias a un enrutador y luego del enrutador a los controladores:

enrutador de paquetes importar ( "base de datos/sql" "net/http" "ejemplo/controladores/usuarios""github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware""github.com/redis/go-redis/v9" "github.com/rs/zerolog" )tipo RoutingHandler struct { // pasar los valores por puntero más abajo en la pila de llamadas // significa que no crearemos una nueva copia, ahorrando memoria log * zerolog . Logger db * sql . DB cache * redis . Client router chi . Router }       // La conexión, el registrador y el caché se inicializan normalmente en la función principal func NewRouter ( log * zerolog.Logger , db * sql.DB , cache * redis.Client , ) ( r * RoutingHandler ) { rtr : = chi.NewRouter ( )         devolver & RoutingHandler { registro : registro , base de datos : base de datos , caché : caché , enrutador : rtr , } }     func ( r * RoutingHandler ) SetupUsersRoutes ( ) { uc : = users.NewController ( r.log , r.db , r.cache )        r . router . get ( "/users/:name" , func ( w http . ResponseWriter , r * http . Request ) { uc . get ( w , r ) }) }      

Luego, puedes acceder a los campos privados de la estructura en cualquier método que sea su puntero receptor, sin violar la encapsulación.

usuarios del paquete importar ( "base de datos/sql" "net/http" "ejemplo/modelos""github.com/go-chi/chi/v5" "github.com/redis/go-redis/v9" "github.com/rs/zerolog" )tipo Controlador estructura { log * zerolog . Logger modelos de almacenamiento . UserStorage caché * redis . Cliente }      func NewController ( log * zerolog.Logger , db * sql.DB , cache * redis.Client ) * Controller { return & Controller { log : log , almacenamiento : models.NewUserStorage ( db ) , cache : cache , } }            func ( uc * Controller ) Get ( whttp.ResponseWriter , r * http.Request ) { // tenga en cuenta que también podemos envolver el registro en un middleware, esto es para fines de demostración uc.log.Info ( ) . Msg ( " Obteniendo usuario " )       parámetro de usuario : = chi . URLParam ( r , "nombre" )   var usuario * modelos . Usuario // obtener el usuario del caché err := uc . cache . Get ( r . Context (), userParam ). Scan ( & usuario ) si err != nil { uc . log . Error (). Err ( err ). Msg ( "Error al obtener el usuario del caché. Recuperando del almacenamiento SQL" ) }         usuario , err = uc.storage.Get ( r.Context ( ), " johndoe" ) si err ! = nil { uc.log.Error ( ) . Err ( err ) .Msg ( " Error al obtener el usuario del almacenamiento SQL" ) http.Error ( w , " Error interno del servidor " , http.StatusInternalServerError ) devolver } }          

Finalmente puedes utilizar la conexión de base de datos inicializada en tu función principal en la capa de acceso a datos:

modelos de paquetes importar ( "base de datos/sql" "tiempo" ) tipo ( estructura UserStorage { conn * sql . DB }    Estructura de usuario { Nombre cadena `json:"name" db:"name,primarykey"` JoinedAt hora . Hora `json:"joined_at" db:"joined_at"` Correo electrónico cadena `json:"email" db:"email"` } )        func NewUserStorage ( conn * sql.DB ) * UserStorage { devuelve & UserStorage { conn : conn , } }      func ( us * UserStorage ) Get ( nombre cadena ) ( usuario * Usuario , err error ) { // asumiendo que 'nombre' es una clave única consulta : = "SELECT * FROM users WHERE nombre = $1"           si err := us . conn . QueryRow ( consulta , nombre ). Scan ( & usuario ); err != nulo { devolver nulo , err }          devolver usuario , nulo }  

Véase también

Referencias

  1. ^ Seemann, Mark. "La inyección de dependencia es un acoplamiento débil". blog.ploeh.dk . Consultado el 28 de julio de 2015 .
  2. ^ ab Seeman, Mark (octubre de 2011). Inyección de dependencia en .NET . Manning Publications. pág. 4. ISBN 9781935182504.
  3. ^ Niko Schwarz, Mircea Lungu, Oscar Nierstrasz, “Seuss: Desacoplamiento de responsabilidades de los métodos estáticos para una configurabilidad de grano fino”, Journal of Object Technology, volumen 11, n.º 1 (abril de 2012), págs. 3:1-23
  4. ^ "HollywoodPrinciple". c2.com . Consultado el 19 de julio de 2015 .
  5. ^ "El patrón de diseño de inyección de dependencia: problema, solución y aplicabilidad". w3sDesign.com . Consultado el 12 de agosto de 2017 .
  6. ^ Erez, Guy (9 de marzo de 2022). "Inversión de dependencias frente a inyección de dependencias". Medium . Consultado el 6 de diciembre de 2022 .
  7. ^ Mathews, Sasha (25 de marzo de 2021). "Simplemente estás inyectando una dependencia, pensando que estás siguiendo la inversión de dependencia...". Medium . Consultado el 6 de diciembre de 2022 .
  8. ^ "Contenedor de IoC de Spring" . Consultado el 23 de mayo de 2023 .
  9. ^ Fowler, Martin. "Contenedores de inversión de control y el patrón de inyección de dependencia". MartinFowler.com . Consultado el 4 de junio de 2023 .
  10. ^ "Inyección de dependencia en NET" (PDF) . philkildea.co.uk . p. 4. Archivado desde el original (PDF) el 2015-07-21 . Consultado el 2015-07-18 .
  11. ^ "¿Cómo explicar la inyección de dependencias a un niño de 5 años?". stackoverflow.com . Consultado el 18 de julio de 2015 .
  12. ^ IT, Titanium. "James Shore: La inyección de dependencia desmitificada". www.jamesshore.com . Consultado el 18 de julio de 2015 .
  13. ^ "Ser "nuevo" o no ser "nuevo"... Archivado desde el original el 13 de mayo de 2020. Consultado el 18 de julio de 2015 .
  14. ^ "Cómo escribir código comprobable". www.loosecouplings.com . Consultado el 18 de julio de 2015 .
  15. ^ "Cómo escribir código limpio y comprobable". www.ethanresnick.com . Consultado el 18 de julio de 2015 .
  16. ^ Sironi, Giorgio. "Cuándo inyectar: ​​la distinción entre nuevos medicamentos e inyectables - Invisible a simple vista". www.giorgiosironi.com . Consultado el 18 de julio de 2015 .
  17. ^ "El canuk urbano, ¿eh?: sobre la inyección de dependencia y la violación de las preocupaciones sobre la encapsulación". www.bryancook.net . Consultado el 18 de julio de 2015 .
  18. ^ "El patrón de diseño de inyección de dependencia". msdn.microsoft.com . Consultado el 18 de julio de 2015 .
  19. ^ ab "Programa Java Community Process(SM) - JSRs: Java Specification Requests - detail JSR# 330" (El programa Java Community Process(SM) - JSR: solicitudes de especificación de Java - detalle JSR# 330). jcp.org . Consultado el 18 de julio de 2015 .
  20. ^ "3.1. Inyección de dependencias: Python 3: de la no dependencia al aprendizaje automático". Archivado desde el original el 8 de febrero de 2020.
  21. ^ abc "Cómo funciona la inyección de dependencia (DI) en el desarrollo de aplicaciones Java Spring - DZone Java".
  22. ^ "Inyección de dependencia e inversión de control en Python — Documentación de Dependency Injector 4.36.2".
  23. ^ "Cómo refactorizar para la inyección de dependencia, parte 3: aplicaciones más grandes".
  24. ^ "Una breve introducción a la inyección de dependencias: qué es y cuándo utilizarla". 18 de octubre de 2018.
  25. ^ "Inyección de dependencia | Professionalqa.com".
  26. ^ "¿Cuáles son las desventajas de usar la inyección de dependencia?". stackoverflow.com . Consultado el 18 de julio de 2015 .
  27. ^ ab "Inversión de inyección de dependencias: Clean Coder". sites.google.com . Consultado el 18 de julio de 2015 .
  28. ^ "Cómo desacoplar su aplicación de su marco de inyección de dependencias". InfoQ . Consultado el 18 de julio de 2015 .
  29. ^ Martin Fowler (23 de enero de 2004). "Contenedores de inversión de control y el patrón de inyección de dependencias: formas de inyección de dependencias". Martinfowler.com . Consultado el 22 de marzo de 2014 .
  30. ^ "AccessibleObject (Java Platform SE 7)". docs.oracle.com . Consultado el 18 de julio de 2015 .
  31. ^ Riehle, Dirk (2000), Diseño de marcos: un enfoque de modelado de roles (PDF) , Instituto Federal Suizo de Tecnología
  32. ^ "Inyección de dependencia != usando un contenedor DI". www.loosecouplings.com . Consultado el 18 de julio de 2015 .
  33. ^ "Black Sheep » DIY-DI » Print". blacksheep.parry.org . Archivado desde el original el 2015-06-27 . Consultado el 2015-07-18 .
  34. ^ "Consejos de primavera: un POJO con anotaciones no es sencillo". Archivado desde el original el 15 de julio de 2015. Consultado el 18 de julio de 2015 .
  35. ^ "Anotaciones en POJO: ¿una bendición o una maldición? | Techtracer". 2007-04-07 . Consultado el 2015-07-18 .
  36. ^ Módulos dinámicos Pro Spring para plataformas de servicios OSGi. APress. 17 de febrero de 2009. ISBN 9781430216124. Recuperado el 6 de julio de 2015 .
  37. ^ "Notas de la versión 1.18 de Go: el lenguaje de programación Go". go.dev . Consultado el 17 de abril de 2024 .
  38. ^ "Awesome Go – inyección de dependencia". Github . 17 de abril de 2024 . Consultado el 17 de abril de 2024 .

Enlaces externos