Os princípios SOLID — DIP

Dependency inversion principle (DIP) — Princípio da inversão de dependência

Continuando do artigo anterior, vamos falar agora sobre o quinto e último princípio, DIP.

O DIP, princípio da inversão de dependência, que muitos chamam de injeção de dependência, diz:

“ Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações”
“Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações”

Em outras palavras, sempre dependa de uma abstração e nunca de uma implementação, ou de uma classe concreta.

Talk is cheap, show me the code

Vamos tentar explicar através do código. Imagine que você possua um e-commerce, e gostaria de enviar e-mails promocionais para seus clientes, de acordo com as preferências e histórico de acesso.

Neste caso, você tem uma classe para MailMarketing que receberá um cliente, monta o e-mail de acordo com o histórico deste cliente e envia.

<?phpclass Mail
{
public function enviar($mensagem)
{
//logica de envio
}
}
class MailMarketing
{
public function enviar(Cliente $cliente)
{
$mensagem = $this->getConteudoEmailPorCliente($cliente);
$mail = new Mail;
$mail->enviar($mensagem);
}
private function getConteudoEmailPorCliente($cliente)
{
//logica de elaboração de conteúdo
}
}

Neste caso, a linha $mail = new Mail; quebra a nossa DIP, pois estamos criando uma instância de Mail , ou seja, uma dependência no nosso código. Qualquer alteração na classe Mail pode quebrar o funcionamento da class MailMarketing .

Aí você pensa em refatorar e jogar a lógica dessa criação para fora, injetando no construtor a instância da classe Mail:

class MailMarketing
{
protected $mail;
public function __construct(Mail $mail)
{
$this->mail = $mail;
}
public function enviar($mensagem)
{
$mensagem = $this->getConteudoEmailPorCliente($cliente);
$this->mail->enviar($mensagem);
}
private function getConteudoEmailPorCliente($cliente)
{
//logica de elaboração de conteúdo
}
}

O código ficou um pouco melhor, pois agora, na criação do objeto já possuímos a instância de Mail criada.

Entretanto, continuamos quebrando o DIP, pois continuamos dependendo de uma classe concreta e não de uma abstração. Para corrigir isso, vamos criar uma interface que será nossa abstração, e as demais classes irão utilizar esta interface. Desta forma, ganhamos flexibilidade na aplicação, pois no caso de querermos utilizar diferentes serviços de e-mail para cada cenário na aplicação, a abstração continua a mesma, porém a implementação fica escondida da nossa classe MailMarketing :

<?phpinterface iMail
{
public function enviar($mensagem);
}
class MailSMTP implements iMail
{
public function enviar($mensagem)
{
//logica de envio
}
}
class MailAmazon implements iMail
{
public function enviar($mensagem)
{
//logica de envio
}
}
class MailChimp implements iMail
{
public function enviar($mensagem)
{
//logica de envio
}
}
class MailMarketing
{
protected $mail;
public function __construct(iMail $mail)
{
$this->mail = $mail;
}
public function enviar(Cliente $cliente)
{
$mensagem = $this->getConteudoEmailPorCliente($cliente);
$this->mail->enviar($mensagem);
}
private function getConteudoEmailPorCliente($cliente)
{
//logica de elaboração de conteúdo
}
}

Com isso, garantimos que aplicação não dependa mais de uma classe concreta específica, e sim de uma abstração, o que proporciona uma flexibilidade muito maior.

Este foi o último dos princípios SOLID. Espero que tenham gostado.

Os códigos estão no repositório: https://github.com/felippeduarte/medium/tree/master/solid

--

--