SOLID #5: Dependency Inversion Principle con C#

En esta publicación veremos como implementar Dependency Inversion Principle usando el lenguaje C#.

Rodríguez Patiño, Eduardo
2020-10-01 | 8,065 lecturas
Actualizado:

Seguro que esto lo venimos haciendo en nuestro día a día y nunca nos hemos dado cuenta.

¿Qué dice el principio?

  • Las clases de alto nivel no deberían depender de las clases de bajo nivel. Ambas deberían depender de las abstracciones.
  • Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones.

¿Pero como que no se entiende mucho no?

Traducción

El problema cuando construimos software es que solemos hacer muchas dependencias y esto conlleva a un futuro que cambiar una pieza de nuestro código obliga a refactorizar todo el proyecto y esto no debería ser así.

Ejemplo de lo malo

Supongamos que luego de crear una orden de compra necesitamos enviar un correo electrónico a nuestro cliente para confirmar su orden y el envío de correo será a traves de MailChimp.

public class MailChimpService 
{
    public void Send() 
    {
        // Todo: código para enviar el correo
    }
}

public class OrderService 
{
    public readonly MailChimpService _mailService;

    public OrderService(MailChimpService mailService) 
    {
        _mailService = mailService;
    }

    public void Create(Order order) 
    {
        // ToDo: código para crear la orden

        // Enviar notificación de la orden creada
        _mailService.Send();
    }
}

Pero eso funciona bien ..

Si funciona bien porque nuestro proveedor actualmente es Mailchimp, pero que pasaría si mañana vamos a trabajar con otro. Pues vamos a tener que cambiar todas las referencias a MailchimpService.

Ejemplo de lo bueno

La solución es invertir los controles y trabajar con la abstracción en vez de la implementación. Hagamos uso de las interfaces para dar solución a este problema.

public interface IMailService 
{
    void Send();
}
public class MailChimpService : IMailService
{
    public void Send() 
    {
        // Todo: código para enviar el correo
    }
}

public class SendGridService : IMailService
{
    public void Send()
    {
        // Todo: código para enviar el correo
    }
}
public class OrderService 
{
    public readonly IMailService _mailService;

    public OrderService(IMailService mailService) 
    {
        _mailService = mailService;
    }

    public void Create(Order order) 
    {
        // ToDo: código para crear la orden

        // Enviar notificación de la orden creada
        _mailService.Send();
    }
}

Ahora nuestra orden es capaz de trabajar con cualquier proveedor de correo porque solo hace uso de la interfaz no de la clase en si.

El cambiar de proveedor de correo ya no es un problema porque ya no tenemos una fuerte dependencia hacia la clase, por lo cual hicimos uso de la inversión de dependencia.