DEV Community

Otavio Augusto
Otavio Augusto

Posted on

Inversion of Control (IoC): o conceito por trás do código desacoplado

Quando começamos a desenvolver software, é muito comum criarmos nossas dependências diretamente dentro das classes.

Algo parecido com isso:

public class UserService
{
    public void Register()
    {
        var emailService = new EmailService();

        emailService.Send("teste@email.com");
    }
}
Enter fullscreen mode Exit fullscreen mode

Funciona.

Mas existe um problema escondido nesse código.

O UserService está assumindo uma responsabilidade que não deveria ser dele: criar suas próprias dependências.

E é justamente aqui que entra um conceito extremamente importante no desenvolvimento de software: Inversion of Control (IoC).


O que é Inversion of Control?

Antes de falar sobre ASP.NET Core ou Dependency Injection, precisamos entender o conceito.

A tradução literal é:

Inversão de Controle

Mas inversão do quê?

Da responsabilidade de criar e gerenciar objetos.

Sem IoC, a própria classe controla tudo.

UserService
    ↓
Cria EmailService
Enter fullscreen mode Exit fullscreen mode

Com IoC, esse controle é transferido para outro componente.

UserService
    ↓
Recebe EmailService
Enter fullscreen mode Exit fullscreen mode

A classe deixa de criar suas dependências e passa apenas a utilizá-las.


O problema de criar dependências manualmente

Vamos analisar novamente este código:

public class UserService
{
    public void Register()
    {
        var emailService = new EmailService();

        emailService.Send("teste@email.com");
    }
}
Enter fullscreen mode Exit fullscreen mode

O que acontece se amanhã você quiser trocar o serviço de e-mail?

Talvez usar SendGrid.

Ou AWS SES.

Ou criar uma implementação para testes.

Será necessário alterar a própria classe.

Isso gera um problema chamado alto acoplamento.

Ou seja:

  • Mais difícil de testar
  • Mais difícil de manter
  • Mais difícil de evoluir

Como o IoC resolve esse problema

Agora imagine o seguinte código:

public class UserService
{
    private readonly IEmailService _emailService;

    public UserService(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void Register()
    {
        _emailService.Send("teste@email.com");
    }
}
Enter fullscreen mode Exit fullscreen mode

Observe que o UserService não cria mais nada.

Ele apenas declara o que precisa para funcionar.

IEmailService
Enter fullscreen mode Exit fullscreen mode

A responsabilidade de criar a dependência foi removida da classe.

O controle foi invertido.

Visualmente, a diferença é esta:


Uma analogia simples

Imagine que você trabalha em um escritório.

Sem IoC:

Você precisa comprar seu computador, instalar tudo, configurar internet e preparar seu ambiente de trabalho.

Com IoC:

Quando você chega, tudo já está pronto.

Você apenas utiliza os recursos necessários para trabalhar.

Foi exatamente isso que aconteceu com a classe.

Ela não se preocupa mais em criar suas dependências.

Ela apenas utiliza aquilo que foi fornecido para ela.


Quais são os benefícios?

Menor acoplamento

As classes passam a depender de contratos, não de implementações concretas.

Facilidade para testes

Você pode substituir implementações reais por mocks ou fakes.

Maior flexibilidade

Trocar uma implementação deixa de exigir alterações em toda a aplicação.

Código mais organizado

Cada classe passa a ter responsabilidades mais bem definidas.


IoC e Dependency Injection são a mesma coisa?

Não.

Essa é uma das maiores confusões entre desenvolvedores iniciantes.

IoC é o conceito.

Dependency Injection é uma das formas de implementar esse conceito.

Pense assim:

IoC = O conceito
DI = Uma implementação desse conceito
Enter fullscreen mode Exit fullscreen mode

Primeiro entendemos a inversão do controle.

Depois utilizamos mecanismos para colocá-la em prática.


Resumo

Sem IoC:

Classe
    ↓
Cria dependências
Enter fullscreen mode Exit fullscreen mode

Com IoC:

Classe
    ↓
Recebe dependências
Enter fullscreen mode Exit fullscreen mode

Em outras palavras:

A classe deixa de se preocupar com como obter suas dependências e passa a focar apenas em executar sua responsabilidade.

Esse conceito é a base de praticamente todo o ecossistema moderno do ASP.NET Core.

E no próximo artigo vamos entender como o framework implementa essa inversão através da Dependency Injection.

Top comments (0)