DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

Descomplicando Inversão de Dependência (Dependecy Inversion Principle)

Introdução

O conceito de Dependency Inversion (DI) ou Inversão da dependência, um dos princípios do SOLID. pode deixar desenvolvedores imaturos confuso, isso porque esse conceito geralmente surge de uma necessidade prática e real e as explicações geralmente possuem níveis de abstrações que exiga a compreensão por completo do fluxo de um sistema.

Antes de entendermos sobre o assunto temos que entender o que são os módulos de baixo e alto nível de um sistema

Módulos de alto e baixo nível

Entender como o sistema de comporta em níveis de módulos e a relação entre eles é de extrema importância para a compreensão do conceito de DI.

Alto nível

O foco aqui é a regra de negócio, lógica central, é aqui que existe o “valor” do que é o sistema. Deve ser algo estável e mudar pouco. Por exemplo: calcular o frete de um pedido, gerar uma fatura ou processar um pagamento.

Baixo nível

O foco é os detalhes de implementação, mecanismos concretos. São os braços e as pernas que executam o que é demandado pelo módulo de alto nível, mas não definem as regras. Isto posto, está mais sujeito a mudanças e alguns exemplos são: bancos de dados específicos, frameworks de interfaces, etc…

Relação entre alto e baixo nível

De forma resumida, podemos dizer que:

Alto nível = o que o sistema faz (regras de negócio).

Baixo nível = como o sistema faz (detalhes técnicos).

Abstração = a ponte que une os dois, mantendo o alto nível protegido dos detalhes.

Didaticamente explicando o conceito:

  • O alto nível diz: “Preciso calcular fretes”
  • O baixo nível responde: “Ok, sei falar com os Correios e calcular o valor”

Se o alto nível depender diretamente dos detalhes (Correios), ele fica preso apenas a um serviço, então se amanhã mudar para FedEx, a alteração deverá ser feita na alta escala do sistema (alto nível), o que é uma péssima prática.

Para resolver a problemática acima, podemos utilizar a seguinte abordagem:

  1. O alto nível só conhece a regra “alguém que calcule frete”
  2. O desenvolvedor cria a abstração ICalculadoraFrete
  3. O baixo nível (Correios ou FedEx) implementa essa abstração
  4. O alto nível não precisa mudar quando trocarmos serviço postal

Inversão de dependência

A ideia central da inversão de dependência é “desamarrar” as regras de negócios a um detalhe específico de implementação. Já que essa prática deixa o sistema rígido e difícil de mudar.

Analogia do dia a dia

  • Sem DI: Um carro que só funciona se você abastecer com a gasolina da “Bandeira X”
  • Com DI: O carro depende apenas da abstação (interface) “combustível líquido inflamável”
    • Pode ser gasolina comum, aditivada, etanol ou até biocombustível

Com base na analogia acima, a gente é capaz de perceber que com a Inversão de dependência o carro não se prende aos detalhe da gasolina (baixo nível), ele só depende da abstração de um combustível

Aplicando o princípio da Inversão de Dependência

Para utilizar a inversão de dependência vamos aplicar a Inversão de Controle (IoC) e Injeção de Dependência (DI)

1. Criamos uma interface (um contrato)

public interface INotificacaoService
{
    void Enviar(string mensagem);
}
Enter fullscreen mode Exit fullscreen mode

Aqui estamos dizendo: "Eu não me importo como a mensagem será enviada. Só quero que exista alguém capaz de executar o método Enviar()." Isso é lindo. Porque o PedidoService não quer saber de e-mail, SMS, WhatsApp, sinal de fumaça... ele só quer enviar.

2. Criamos implementações dessa interface

Enviar por E-mail:

public class EmailService : INotificacaoService
{
    public void Enviar(string mensagem)
    {
        Console.WriteLine("Enviando Email: " + mensagem);
    }
}
Enter fullscreen mode Exit fullscreen mode

3. PedidoService não se importa mais com o como

Agora ele só recebe a dependência via construtor:

public class PedidoService
{
    private readonly INotificacaoService _notificacaoService;

    // INJEÇÃO DE DEPENDÊNCIA VIA CONSTRUTOR
    public PedidoService(INotificacaoService notificacaoService)
    {
        _notificacaoService = notificacaoService;
    }

    public void FinalizarPedido()
    {
        _notificacaoService.Enviar("Pedido finalizado!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)