Vamos tentar entendê-lo através dos dois exemplos.
Exemplo 1
Nos primeiros dias, os aplicativos eram usados para gerar prompts de comando para aceitar as entradas do usuário uma após a outra. Hoje, as estruturas de UI instanciam vários elementos da interface do usuário, percorrem vários eventos desses elementos da interface do usuário (como passar o mouse, clique etc.) e o usuário / programas principais fornece ganchos (por exemplo, ouvintes de eventos da UI em Java) para escutar esses eventos. Assim, o fluxo de elemento da interface do usuário principal "control" é movido do programa do usuário para a estrutura da interface do usuário. Nos dias anteriores, estava no programa do usuário.
Exemplo 2
Considere a classe CustomerProcessor
abaixo:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Se eu quiser que processCustomer()
seja independente de qualquer implementação de getAllCusts()
, não apenas da fornecida por SqlCustRepo
, precisarei me livrar da linha: SqlCustRepo custRepo = new SqlCustRepo()
e substituí-la por algo mais genérico, capaz de aceitar um tipo variado de implementação, de forma que o processCustomers()
simplesmente funcione para qualquer implementação fornecida.
O código acima (instanciando a classe requerida SqlCustRepo
pela lógica do programa principal) é uma maneira tradicional e não atinge essa meta de desacoplar processCustomers()
da implementação de getAllCusts()
. Na inversão de controle, o contêiner instancia a classe de implementação requerida (como especificado por, digamos, configuração xml), injeta na lógica principal do programa que fica vinculada conforme os ganchos especificados (digamos por @Autowired
annotation ou getBean()
method na mola framework).
Vamos ver como isso pode ser feito. Considere o código abaixo.
Config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="custRepo" class="JsonCustRepo" />
</beans>
CustRepo.java
interface ICustRepo
{ ... }
JsonCustRepo.java
class JsonCustRepo implements CustRepo
{ ... }
App.java
class App
{
public static void main(String[] args)
{
ApplicationContext context = new ClassPathXmlApplicationContext("Config.xml");
ICustRepo custRepo = (JsonCustRepo) context.getBean("custRepo");
}
}
Também podemos ter
class GraphCustRepo implements ICustRepo { ... }
e
<bean id="custRepo" class="GraphCustRepo">
e não precisaremos alterar o App.java.
Acima do contêiner (que é o framework Spring) tem a responsabilidade de escanear o arquivo xml, instanciar o bean de um tipo específico e injetá-lo no programa do usuário. O programa do usuário não tem controle sobre qual classe é instanciada.
PS: IoC é um conceito genérico e é alcançado de várias maneiras. Exemplos acima alcançados por injeção de dependência.
Referência: artigo de Martin Fowler .