Dependecy Inversion Principle - PHP

Vamos a estudiar el principio de inversión de dependencia con ejemplos en PHP.

Rodríguez Patiño, Eduardo
2020-09-27 | 287 lecturas

Es muy probable que esto lo vengamos haciendo en frameworks como laravel que se suele usar el patrón de inyección de dependencia que se basa en este principio.

Alta dependencia

Cuando construimos software orientado a objetos solemos encapsular la lógica en clases independientes. El problema es que instanciamos estas clases en otras clases y al final generamos un alto acomplamiento porque el cambiar la clase actual por otra obliga a refactorizar todo el proyecto.

Ejemplo

Vamos a ver un ejemplo que clarifique el problema que rompe este principio.

Supongamos que luego de crear nuestra orden de compra queremos mandar un correo electrónico para notificar a nuestro cliente sobre su orden creada y lo hacemos a través del proveedor Mailchimp.

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

El uso de este sería de la siguiente manera.

class OrderService 
{
    private MailChimpService $mailService;

    public function __constructor (MailChimpService $mailService) 
    {
        $this->mailService = $mailService;
    }

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

        // Enviar notificación de la orden creada
        $this->mailService.Send();
    }
}

Todo bien pero ..

Mañana nos piden que cambiemos de proveedor a SendGrid porque nos está dando un mejor precio. Asimismo, la clase MailChimpService ya esta instanciada en varias partes de nuestro proyecto lo cual si queremos cambiar esto tocaría modificar todo.

Solución

Trabajar con la abstracción en vez de la implementación para evitar este problema y tener un código más escalable.

interface IMailService 
{
    function send(): void;
}

class MailChimpService implements IMailService
{
    public function send(): void
    {
        // Todo: código para enviar el correo
    }
}

class SendGridService implements IMailService
{
    public function send(): void
    {
        // Todo: código para enviar el correo
    }
}

Y nuestro OrderService quedaría de esta forma.

class OrderService 
{
    private IMailService $mailService;

    public function __constructor (IMailService $mailService) 
    {
        $this->mailService = $mailService;
    }

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

        // Enviar notificación de la orden creada
        $this->mailService.Send();
    }
}