Inyección de dependencias ¿Qué es y para qué sirve?
Aprende a implementar la inyección de dependencias con ejemplos prácticos en C# 🚀

Dependencias

Primero debemos tener claro que es una dependencia, y la verdad es que es un comportamiento entre clases, por ejemplo cuando una clase A utiliza una clase B, se dice que la clase B es una dependencia de la clase A, en términos prácticos cuando tengo un método en la clase A que necesita un objeto de la clase B, es decir una instancia de esta, entonces hay una dependencia.

Acoplamiento

Las dependencias son inevitables entre clases, sin importar la complejidad del proyecto a desarrollar y a su vez generan una característica conocida en la ingeniería de software como Acoplamiento y puede ser alto o bajo. El acomplamiento alto se da cuando hay una dependencia poco flexible entre clases, como en el siguiente código:

public class Poblacion
{
   public void comunicarse(){
      Animales animal = new Animales();
      animal.emitirSonido();
   }
}

Como notamos en la línea resaltada hay una dependencia entre las clases Poblacion y Animales, y en un método de la clase Poblacion llamado comunicarse se instancia a Animales, he allí la dependencia y es una dependencia fuerte lo que genera un acoplamiento alto, esto en general es una práctica no recomendada porque no hay forma de utilizar el método comunicarse de la clase Poblacion sin usar la clase Animales, ahí está la dependencia fuerte y además escondida.

El acoplamiento bajo lo logramos cuando hacemos fácil intercambiar dependencias y una de las mejores maneras de hacerlo es usando inyección de dependencias.

Inyección de dependencias

Es una técnica mediante la cual las dependencias de un objeto son provistas por otro objeto, y esto lo hacemos vía el constructor (más información de constructores en esta entrada anterior 😉). Aplicando esto en el código de arriba quedaría así:

public class Poblacion
{
   private readonly Animales animal;

   //constructor
   public Poblacion(Animales animal){
      this.animal = animal;
   }
   
   public void comunicarse(){
      animal.emitirSonido();
   }
}

Codificando de esta forma más optimizada lo que estamos haciendo es obligando a que cada vez que vayamos a usar la clase Poblacion le pasaremos la clase de la cual depende, en este caso Animales. Y decimos que es mejor que la forma anterior porque ahora la dependencia entre ambas clases es explícita y con esto hemos bajado el nivel de acoplamiento, pero podemos mejorar aún más el código.

Interfaces

Si nos dimos cuenta con el código anterior es que lo hemos mejorado respecto de su versión inicial, sin embargo la clase Poblacion aún depende en cierta medida de la clase Animales y cambiar las dependencias no sería del todo fácil ya que implica tener que cambiar todos los constructores donde esté declarada la clase Animales, para solucionar esto hacemos uso de las interfaces, que nos van a permitir hacer aún más flexible las dependencias entre clases, crearemos una interfaz:

public interface ISerVivo{
   void emitirSonido();
}

Ahora hacemos que la clase Animales la implemente, y crearemos una tercera clase llamada Personas:

public class Animales : ISerVivo
{
   public void emitirSonido(){
      //...
   }
}
public class Personas : ISerVivo
{
   public void emitirSonido(){
      //...
   }
}

Ahora en nuestra clase Poblacion cambiamos Animales por ISerVivo:

public class Poblacion
{
   private readonly ISerVivo serViviente;

   //constructor
   public Poblacion(ISerVivo serViviente){
      this.serViviente= serViviente;
   }
   
   public void comunicarse(){
      serViviente.emitirSonido();
   }
}

Ahora cuando queremos instanciar una clase Población podemos hacerlo tanto con Animales, como con Personas, hemos ganado esa flexibilidad:

Poblacion pueblo = new Poblacion(new Animales());
Poblacion pueblo = new Poblacion(new Personas());

Ninguna de las dos formas nos dará un error porque ambas clases están implementando la interfaz ISerVivo, entonces tenemos un bajo acoplamiento y una flexibilidad superior, además que las dependencias quedan explícitas en el código ni bien creamos una instancia de la clase Población y una vez pasado el objeto Animales o Personas no necesitamos crear más instancias dentro de sus métodos como antes cuando estaban "ocultas" (ver la línea resaltada del primer trozo de código).

Como hemos visto es una buena práctica usar Inyección de dependencias al programar, y en general hará nuestro código más limpio y de calidad, a practicar dev, en los distintos escenarios donde puedas aplicarlo, y recuerda compartir esta entrada de blog, difunde el conocimiento y también puedes dejarme tus comentarios o sugerencias en la caja de comentarios, hasta la próxima crack! 😊

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *