Vamos tentar entender isso através dos dois exemplos.
Exemplo 1
Nos dias anteriores, os aplicativos costumavam gerar prompts de comando para aceitar entradas do usuário, uma após a outra. Hoje, as estruturas de interface do usuário 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 os programas usuário / principal fornecem ganchos (por exemplo, ouvintes de eventos da interface do usuário em Java) para ouvir esses eventos. Portanto, o fluxo principal "controle" do elemento da interface do usuário é 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 processCustomer()
ser independente de qualquer implementação getAllCusts()
, e não apenas a fornecida por SqlCustRepo
, precisarei me livrar da linha: SqlCustRepo custRepo = new SqlCustRepo()
e substituí-la por algo mais genérico, capaz de aceitar vários tipos de implementação, de modo que processCustomers()
simplesmente funcione para qualquer implementação fornecida. O código acima (instanciar a classe requerida SqlCustRepo
pela lógica do programa principal) é uma maneira tradicional e não atinge esse objetivo de se separar processCustomers()
da implementação de getAllCusts()
. Na inversão de controle, o contêiner instancia a classe de implementação necessária (conforme especificado por, digamos, configuração xml), injeta-a na lógica principal do programa que é vinculada conforme os ganchos especificados (digamos, por @Autowired
anotação ou getBean()
método na estrutura de primavera).
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");
}
}
Nós 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 é a estrutura da primavera) tem a responsabilidade de verificar o arquivo xml, instanciar o bean de 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. Os exemplos acima o alcançam por injeção de dependência.
Referência: artigo de Martin Fowler .