Inyección de Dependencias

Qué es y por que deberías utilizarla

Jonathan Batres
6 min readOct 23, 2021

¿Qué es la inyección de dependencias?

Es un patrón de diseño que consiste en suministrarle a una clase los objetos que necesita en lugar de ser ella misma la responsable de crearlos. Estos objetos contienen métodos que nuestra clase necesita para poder funcionar, de ahí el concepto de dependencia.

Un ejemplo de mundo real (Alto acoplamiento)

Imagínate que un músico se encuentra en su cuarto de hotel y de pronto quiere tocar su instrumento, una guitarra. Obviamente él necesita tener la guitarra en sus manos para poder tocarla y producir sonido 🙂🎸 pero, en ese momento no hay una guitarra en el cuarto y peor aún, no hay nadie que pueda proporcionarle una… sin embargo, descubre que en la mesa hay unos planos con el título “como construir su propia guitarra” el músico se pone manos a la obra, toma los planos y comienza a armarse su propio instrumento para poder tocarlo. Tan descabellado como suena este escenario es como hasta hace unos años se resolvían las dependencias de nuestras clases al momento de codificar. Veamos un ejemplo:

En el siguiente código podernos ver que la clase Musico contiene el método TocarInstrumento( ) que a su vez requiere (Es decir: DEPENDE) de una instancia de la clase Guitarra (O dicho de otro modo: De un objeto del tipo Guitarra) ya que la clase Guitarra contiene el método ProducirSonido( )

La clase Guitarra define el método ProducirSonido( ) el cual devuelve un string con el sonido que produce una guitarra (Bueno, más o menos 😁)

Al crear un objeto del tipo Musico y llamar a su método TocarInstrumento( ) este a su vez llama al método ProducirSonido( ) que se encuentra en el objeto del tipo Guitarra lo cual se hace evidente si vemos nuestra salida por consola.

En resumen: “El músico depende de una guitarra para producir sonidos y realizar la acción de tocar su instrumento”.

¡Dependency Injection al rescate!

Lo ideal y lógico sería que cuando el músico desee tocar su instrumento venga su asistente y le proporcione una guitarra ya armada, afinada y lista para ser tocada. Al músico no le interesa (O al menos no debería) saber cómo se armó su instrumento, tampoco tendría que ser responsable de armarse su propia guitarra desde cero cada vez que quiera tocar una ¿Estamos de acuerdo?

En C# esto puede resolverse aplicando el patrón Dependency Injection, inyectando el objeto guitarra en el constructor de la clase Musico. Desde .NET Core en adelante ya existe un contenedor de dependencias propio que se encarga de instanciar los objetos que necesitamos para luego ser inyectados en nuestras clases como servicios. Este proceso sería como que el asistente le proporcione la guitarra al músico 😎 Veamos un ejemplo:

Primero configuramos nuestro contenedor de dependencias que se encargará de resolver las dependencias en tiempo de ejecución. En este caso services.AddTransient<Guitarra, Guitarra>( ); significa en pocas palabras “Cada vez que necesite una guitarra dame una guitarra”

Nuestra clase Guitarra no ha cambiado

La clase Musico ahora recibe el objeto guitarra mediante el constructor, es decir, estamos inyectando la dependencia por medio del constructor liberando así a la clase Musico de tener la responsabilidad de crear (Instanciar) el objeto guitarra.

El método TocarInstrumento( ) de la clase Musico ya no necesita crear una instancia de la clase Guitarra pues al ser inyectada mediante el constructor automáticamente se asigna a la variable de clase _guitarra y está lista para ser utilizada.

Ahora al crear una instancia de la clase Musico debemos enviar como parámetro un objeto del tipo guitarra. Veamos el resultado:

En resumen: Nuestra salida por consola sigue funcionando correctamente con la ventaja que hemos ganado flexibilidad ya que ahora la clase Musico se libera de la responsabilidad de crear objetos del tipo Guitarra, a esto se le llama bajo acoplamiento. PERO…

¡Todavía podemos hacerlo mejor! (Interfaces)

Hemos mejorado la implementación de nuestro código respecto a su versión original sin embargo, nuestra clase Musico aún depende en cierta forma de la clase Guitarra. Imagina que queremos formar una banda con tres músicos y cada uno de ellos toca un instrumento diferente, tendríamos que pasarle a cada músico un instrumento diferente como parámetro y eso aunque no está mal es poco flexible pues estamos “amarrando” al músico a un instrumento en concreto (Y qué tal si un músico pudiese tocar varios instrumentos). Para solucionar este dilema utilizaremos Interfaces y ahora en lugar de pasar como parámetro un instrumento concreto (guitarra, bajo, batería, etc) pasaremos como parámetro un Instrumento Musical (Un concepto abstracto) 🤯 Veamos como aplicarlo:

Lo primero que haremos será definir nuestra interface IInstrumentoMusical la cual contiene la firma del método ProducirSonido( ) pues ya sabemos que todo instrumento musical produce sonido (En C# por convención las interfaces comienzan con la letra “I”)

Luego la clase Guitarra implementa la interfaz IInstrumentoMusical y por tanto también debe definir el método ProducirSonido( ) contenido en nuestra interface pero adaptado a si misma (El sonido que produce una guitarra es diferente al que produce un bajo o una batería)

Lo mismo ocurre con la clase Bajo que implementa la interface IInstrumentoMusical e implementa el método ProducirSonido( ) según sus propias particularidades.

De igual forma para la clase Bateria

Nuestro contenedor de dependencias quedaría de la siguiente manera definiendo una configuración por cada clase que implementa la interface IInstrumentoMusical.

Ahora en el constructor de la clase Musico inyectamos un instrumento musical, concepto abstracto, el cual engloba: guitarras, bajos, baterías etc. Mira que maravilloso ¡Ya no dependemos de un instrumento en concreto!

¡Ahora sí podemos crear nuestra banda! Vemos como la clase Musico puede recibir como parámetros un objeto del tipo Guitarra, Bajo y Bateria esto es así porque ahora el músico espera recibir un instrumento musical y tanto la guitarra, el bajo y la batería lo son (Pues todas implementan la interface IInstrumentoMusical)

Finalmente podemos ver como cada uno de nuestros músicos toca su instrumento produciendo el sonido característico de cada uno 🤗

En conclusión

  1. La Inyección de Dependencias libera a nuestras clases de la responsabilidad de crear ellas mismas los objetos que necesitan obteniendo así un bajo acoplamiento entre clases, ganado flexibilidad y mantenibilidad en nuestro código.
  2. Las Interfaces nos ayudan a aumentar aún más el poder de la Inyección de Dependencias permitiéndonos programar en base a abstracciones y no a “cosas” concretas.
  3. Si quieres profundizar más en el tema de Interfaces mira esto.

Fuentes

Nota: Muchas gracias por leer este pequeño artículo. La Inyección de Dependencias fue un concepto que me costó mucho comprender en su momento y solo imaginando ejemplos así pude llegar a entenderla (PD. No soy bueno para las definiciones rigurosamente técnicas 😅) Así que espero que estos ejemplos te hayan ayudado aunque sea un poco.

--

--

Jonathan Batres
Jonathan Batres

No responses yet