Inversión de dependencias

Hemos llegado ya al último punto de los principios SOLID el cual es la inversión de dependencias. 

En .NET cumplimos este principio utilizando inyección de dependencias. Lo más normal es ver la inversión de dependencias en aplicaciones web, pero también podemos utilizarla en aplicaciones de consola.

La única diferencia, es que desde .NET Core, cuando creamos una aplicación web, la clase que va a contener las dependencias viene creado por defecto y es muy fácil añadir nuevas dependencias en el, mientras que en una aplicación de consola, hay que crearlo manualmente. 

Más adelante veremos cómo funcionan ambas.

 

1 - Qué es el principio de inversión de dependencias. 

El principio de inversión de dependencias es utilizado para permitirnos crear clases que están acopladas entre sí de una forma sencilla. 

Este principio, nos indica que debemos separar la lógica en módulos o servicios que puedan ser reutilizados y en caso de tener que modificarlos, únicamente esos servicios se verán afectados. 

De esta forma quitamos también parte de la responsabilidad sobre nuestra clase. 

Los principios SOLID están relacionados todos entre sí, el principio de inversión de dependencias se nutre de la interfaces que hemos visto a lo largo de los módulos previos.

 

2 - Utilizar inversión de dependencias

Como he indicado antes, en .NET la forma de utilizar inversión de dependencias es a través de la inyección de dependencias. 

Y lo que tenemos que hacer, como su nombre indica es Inyectar estas dependencias en nuestros servicios. 

 

Para ello lo realizamos a través del constructor. 

public class AlmacenamientoFichero : IAlmacenamiento
{
    readonly IFicheroInformacion _ficheroInformacion;

    public AlmacenamientoFichero(IFicheroInformacion ficheroInformacion)
    {
        _ficheroInformacion = ficheroInformacion;
    }
    //Resto de métodos
}

Como vemos estamos inyectando a través del constructor la interfaz IFicheroInformacion la cual contiene el método el cual nos permite consultar la información de un fichero. Pero “no sabemos” cómo está implementado, o las dependencias de esa otra clase, ya que está abstraída a través de una interfaz.  

 

Como puedes observar ahora el constructor recibe un parámetro, y cuando instanciamos la clase, deberíamos pasarlo, pero no lo haremos, ya que todo nuestro código va a estar cortado por el principio de inversión de dependencias.

Por lo que debemos inyectar las dependencias en todas nuestras clases.

public class ArticulosServicio
{
    private readonly Cache _cache;
    private readonly ILogging _logging;
    private readonly IAlmacenamiento _almacenamiento;

    public ArticulosServicio(IAlmacenamiento almacenamiento, ILogging logging, Cache cache)
    {
        _logging = logging;
        _almacenamiento = almacenamiento;
        _cache = cache;
    }

   //resto de métodos
    
}

 

3 - Inyección de dependencias en .NET

Debido a que realizare un post más en detalle sobre inyección de dependencias en el futuro. voy a pasar solo por encima, para que nuestro código entienda a qué clase hace referencia cada interfaz.

 

3.1 - Inyeccion de dependencias en ASP.NET Core

Desde la salida de Net Core tenemos un contenedor de dependencias para asp.net en el core del sistema, al cual podemos acceder desde el fichero/clase startup.cs en el método ConfigureServices. simplemente debemos indicar services.AddScoped<Interface, Class>.

De esta forma cuando el código llegue a un constructor que contiene dicha interfaz, sabrá a qué clase le hace referencia. 

services.AddScoped<IAlmacenamiento, AlmacenamientoSQL>()
    .AddScoped<ILogging, Logging>()
    .AddScoped<DBRepository>()
    .AddScoped<Cache>();

 

3.2 - Inyección de dependencias en una aplicación de consola. 

El objetivo es el mismo que en el ejemplo de ASP.NET pero en este caso debemos construir el contendor de las dependencias nosotros mismos.

Para ello debemos utilizar los dos siguientes paquetes:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

De esta forma tendremos acceso a la clase ServiceCollection la cual nos permite construir nuestras dependencias con el método BuildServiceProvider.

//Base
var serviceProvider = new ServiceCollection()
    .AddScoped<Interface, Clasesservicio>()
    .BuildServiceProvider();

var servicio = serviceProvider
    .GetService<Interface>();


//Ejemplo en nuestro código
var serviceProvider = new ServiceCollection()
    .AddScoped<IAlmacenamiento, AlmacenamientoFichero>()
    .BuildServiceProvider();

var servicio = serviceProvider
    .GetService<IAlmacenamiento>();

nota: veremos la diferencia entre scoped, singleton, transient en otro post. 

 

4 - Beneficios de implementar inversión de dependencias 

Gracias a la inversión de dependencias podemos crear clases más pequeñas e independientes, permitiéndonos además, reutilizar lógica de una forma muy sencilla. Lo cual es su mayor ventaja en mi opinión.

Agregar inversión de dependencias nos proporciona flexibilidad y estabilidad a la hora de desarrollar nuestras aplicaciones. Ya que estaremos más seguros a la hora de ampliar funcionalidades, etc.

Como última gran ventaja, utilizar inversión de dependencias nos permite la creación de test unitarios  con mucha más facilidad, permitiéndonos crear mock de las mismas. 

 

Conclusión

Finalmente decir que sí, debemos implementar inversión de dependencias en todos nuestros proyectos ya que eso nos dará servicios más reusables y fáciles de implementar en otros servicios. 

Con este post hemos visto todos los principios SOLID, los cuales siguiendolos a rajatabla nos permiten crear aplicaciones robustas que van a estar muy bien creadas para adaptarlas a futuros cambios.