Quem estuda desenvolvimento provavelmente já ficou confuso pelo menos uma vez com estes três termos: DI, IoC e DIP.
Quando cursos e artigos dizem algo como “um contêiner IoC injeta dependências por meio de DI para seguir o DIP”, fica fácil perder a noção do que cada termo significa.
Vamos começar pela conclusão: os três termos estão em níveis diferentes. DIP é o princípio — por que fazer isso. IoC é a direção geral que realiza esse princípio — quem tem o controle. DI é a técnica concreta que implementa essa direção — como fornecer a dependência.
Depois de ler este artigo, você vai entender como os três conceitos se relacionam e poderá responder sem hesitar a perguntas de entrevista sobre eles. Também mantive os exemplos de código o mais curtos possível.
Os três termos resumidos em uma linha
É muito mais fácil começar memorizando uma linha para cada termo.
- DIP (Dependency Inversion Principle, princípio da inversão de dependência): princípio de design que recomenda depender de abstrações, como protocolos, em vez de implementações concretas.
- IoC (Inversion of Control, inversão de controle): uma estrutura em que o framework ou contêiner controla o fluxo do programa, e não o seu código.
- DI (Dependency Injection, injeção de dependência): técnica que fornece os objetos necessários externamente, em vez de criá-los internamente.
A relação entre os três é esta.
DIP é o objetivo e o princípio; IoC é o conceito mais amplo para alcançar esse objetivo; e DI é uma das formas concretas de implementar IoC.
Em outras palavras, o nível de abstração diminui nesta ordem: DIP > IoC > DI.
DIP trata de “do que depender”
DIP é o D de SOLID, o princípio da inversão de dependência entre os cinco princípios fundamentais de design orientado a objetos.
A ideia central tem duas partes: módulos de alto nível não devem depender de módulos de baixo nível, e ambos devem depender de abstrações.
Parece complicado, mas fica bem mais simples no código.
Veja um exemplo ruim em que um serviço de pedidos está diretamente ligado a um provedor de pagamento específico, o Kakao Pay.
// Exemplo ruim: dependência direta de uma classe concreta
class OrderService {
private let pay = KakaoPay() // Para trocar o provedor de pagamento, é preciso desmontar esta parte
}
Para mudar depois para o Naver Pay, você teria que alterar diretamente o código do OrderService. Cada novo meio de pagamento abalaria o módulo de alto nível.
O DIP inverte essa situação. Você define uma abstração para pagamento, um protocolo, e depende apenas dela.
protocol PayGateway { func pay(amount: Int) }
class OrderService {
private let pay: PayGateway // Dependa de uma abstração, não de uma classe concreta
init(pay: PayGateway) { self.pay = pay }
}
Seja Kakao Pay ou Naver Pay, basta implementar PayGateway; o OrderService não precisa ser alterado. É isso que significa inverter a direção da dependência.
IoC trata de “quem tem o controle”
IoC, ou inversão de controle, é um conceito um pouco mais amplo.
Normalmente, o código que escrevemos controla todo o fluxo: criamos objetos, chamamos métodos e definimos a ordem de execução.
IoC inverte esse controle. Em vez de nós chamarmos o framework, o framework nos chama.
Também é conhecido como “Princípio de Hollywood”: “Não nos chame, nós ligaremos para você (Don’t call us, we’ll call you).”
Com um contêiner de DI como o Swinject, o contêiner cria, gerencia e conecta os objetos em vez de você criá-los diretamente. O controle passa de você para o contêiner.
Há um ponto importante aqui: IoC não se limita a DI.
- Um framework chamando um callback
- O padrão Template Method
- O UIKit chamando métodos de ciclo de vida como viewDidLoad por você
Tudo isso são exemplos de IoC. DI é apenas um subconceito especializado em “fornecer dependências”.
DI trata de “como fornecer dependências”
DI, ou injeção de dependência, é a técnica mais representativa para implementar IoC.
No exemplo anterior de DIP, o OrderService recebia PayGateway pelo inicializador. Isso é DI: fornecer de fora um objeto necessário, em vez de criá-lo internamente.
Há três formas principais de injeção.
| Forma de injeção | Descrição | Recomendação |
|---|---|---|
| Injeção pelo construtor | Receber a dependência por init | Mais recomendada (imutável, dependências obrigatórias explícitas) |
| Injeção por método | Receber como parâmetro do método | Para dependências opcionais |
| Injeção por propriedade | Atribuir à propriedade após a criação | Não recomendada, pois se torna opcional e var |
No Swift, recomenda-se a injeção pelo inicializador. A dependência pode ser fixada com let, o que é mais seguro, e é fácil fornecer objetos falsos (Mocks) nos testes.
A relação pode ser resumida assim.
Para seguir o princípio DIP, transferimos o controle na direção do IoC e usamos DI como meio concreto.
Esta frase resume da forma mais concisa a relação entre os três termos.
Perguntas frequentes
P. DI e IoC não são a mesma coisa?
Não. IoC é o conceito mais amplo, enquanto DI é uma das várias formas de implementar IoC. Toda DI é IoC, mas nem todo IoC é DI.
P. Seguir o DIP significa usar DI automaticamente?
Não necessariamente. DIP é o princípio de “depender de abstrações”; DI ocorre quando uma implementação dessa abstração é fornecida externamente. Princípio e técnica são coisas diferentes.
P. Posso usar DI sem uma biblioteca como o Swinject?
Sim. Passar a dependência diretamente pelo inicializador, como no exemplo de Swift acima, também é DI. Swinject e Factory apenas automatizam o processo; a DI não exige uma biblioteca.
Em resumo: DIP é por quê, o princípio; IoC é quem, o controle; e DI é como, a técnica. Separar as três perguntas dessa forma evita confusão.
Quando você entende que estão em níveis diferentes, o código relacionado a DI passa a parecer completamente diferente. Espero que este artigo tenha ajudado a organizar tudo com clareza. Força!
Continue lendo
- O que é injeção de dependência (DI)? Começando por tirar o new de dentro da classe (guia completo com exemplos e analogias)
- Por que Singleton atrapalha os testes e como resolvemos isso com injeção de dependência
- [SOLID #2] Princípios SOLID na prática, parte 2: ISP, DIP e por que a injeção de dependência existe

