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:
- O alto nível só conhece a regra “alguém que calcule frete”
- O desenvolvedor cria a abstração
ICalculadoraFrete
- O baixo nível (Correios ou FedEx) implementa essa abstração
- 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);
}
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);
}
}
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!");
}
}
Top comments (0)