Question:
Sometimes it seems that we are talking about the same thing (of course, we are not) when these concepts are being used. What is the real difference between them? When to use one or the other?
Answer:
Inversion of Control (or IoC) is a broader term to refer to a behavior (explained below). There are several ways to implement inversion of control.
Dependency Injection is no longer such a broad thing, it's actually even considered a design pattern.
Dependency Injection is one of the ways to do Inversion of Control. So "When to use one or the other" doesn't make much sense.
But confusion is very common, it is not uncommon to find the terms being used interchangeably.
I believe that explaining one and then the other demystifies this confusion.
Inversion of Control (IoC)
Inversion of control is a behavior present when using some frameworks. Basically the idea is to separate *what* from *when*.
Two examples (abstract code) follow, the usual way and the one with IoC.
usual form
perguntarNome()
lerEntrada()
perguntarIdade()
lerEntrada()
SE verificarSeDadosEstaoValidos()
ENTAO cadastrar()
SENAO exibirMensagemDeErro()
With IoC
quandoPerguntarNome(lerEntrada)
quandoPerguntarIdade(lerEntrada)
paraVerificarValidade(verificarSeDadosEstaoValidos)
paraCadastrar(cadastrar)
quandoHouverErro(exibirMensagemDeErro)
In the second example we decouple what will be done with when it will be done; we separate the implementations from the flow. This way it is easier to reuse or change just some part of the code (without having to modify/understand *the whole*).
Notice that there is a gap to fit several programming concepts, such as object-oriented principles, event-oriented design, among other things.
I will stop here; this is in essence what we call Inversion of Control .
Dependency Injection
Dependency Injection is one of the ways to perform Inversion of Control.
The technique consists of passing the dependency (the service) to the dependent (the client). This is called injection. The important thing is to understand that we inject the service into the client, instead of the client looking for and building the service he will use.
I think nothing better than a practical example to understand this concept. Below is a (simplified) real example that I have already implemented in one of the systems I worked on (C# code):
public interface ILogger
{
void Logar(string mensagem);
}
public class LogEmArquivo : ILogger
{
void Logar(string mensagem)
{
// Loga a mensagem em um arquivo de log
}
}
public class LogPorEmail : ILogger
{
void Logar(string mensagem)
{
// Envia a mensagem por email aos responsáveis
}
}
public class Principal
{
private ILogger _logger;
public Principal(ILogger logger)
{
_logger = logger;
}
// Chamado pelos métodos internos da classe Principal
// quando há necessidade de logar alguma informação
private void LogarInformacao(string informacao)
{
_logger.Logar(informacao);
}
}
The Principal
class needs an ILogger
to work, but it doesn't "see" or build the implementation that it will use, that's up to whoever will build the Principal
class. This way the implementation of the log action is decoupled from whatever the main class is going to do.
As I said, this is a real example that I came to use. In my case, the application had in the configuration file a directive indicating the environment in which it was being executed (Development, Tests, Homologation, Production…). When starting, the application checked which environment and, according to this configuration, uses a different logger for each environment. Basically in Development and Testing we used only a log file, while in Homologation and Production we used email sending (where the problems were more serious).
At runtime, programmatically, the application changed its implementation of the logger to be used. This is one of the advantages of having the code decoupled.
Reading
One of the forerunners to discuss the topic is author Martin Fowler. For those who want to delve deeper into the topic, you should read the articles on the subject on his blog: