Parece haver muita confusão sobre o padrão de Inversão de Controle (IoC). Várias pessoas o equipararam ao Padrão de Estratégia ou a um Modelo de Componentes, mas essas comparações não captam realmente o que é a IoC. IoC é realmente sobre como uma dependência é obtida. Deixe-me lhe dar um exemplo:
class Game {
void Load() {
this.Sprite.Load(); // loads resource for drawing later
}
}
class Sprite {
void Load() {
FileReader reader = new FileReader("path/to/resource.gif");
// load image from file
}
}
No exposto acima, é claro que Sprite.Load
depende de a FileReader
. Quando você deseja testar o método, precisa do seguinte:
- Um sistema de arquivos em vigor
- Um arquivo de teste para carregar do sistema de arquivos
- Capacidade de acionar erros comuns do sistema de arquivos
Os dois primeiros são óbvios, mas se você deseja garantir que o tratamento de erros funcione conforme o esperado, você também precisa do número 3. Nos dois casos, você potencialmente diminuiu bastante os testes, pois agora eles precisam ir para o disco e você provavelmente tornou seu ambiente de teste mais complicado.
O objetivo da IoC é dissociar o uso do comportamento de sua construção. Observe como isso difere do padrão de estratégia. Com o padrão Estratégia, o objetivo é encapsular um pedaço reutilizável de comportamento, para que você possa estendê-lo facilmente no futuro; não tem nada a dizer sobre como as estratégias são construídas.
Se reescrevéssemos o Sprite.Load
método acima, provavelmente terminaríamos com:
class Sprite {
void Load(IReader reader) {
// load image through reader
}
}
Agora, dissociamos a construção do leitor de seu uso. Portanto, é possível trocar um leitor de teste durante o teste. Isso significa que seu ambiente de teste não precisa mais de um sistema de arquivos, arquivos de teste e pode simular facilmente eventos de erro.
Observe que eu fiz duas coisas na minha reescrita. Eu criei uma interface IReader
que encapsulava algum comportamento - ou seja, implementava o padrão de estratégia. Além disso, mudei a responsabilidade de criar o leitor certo para outra classe.
Talvez não precisemos de um novo nome de padrão para descrever o acima. Parece-me uma mistura dos padrões de Estratégia e Fábrica (para contêineres IoC). Dito isto, não tenho certeza de que motivos as pessoas estão contestando esse padrão, pois fica claro que ele resolve um problema real e, certamente, não é óbvio para mim o que isso tem a ver com Java.