Tratemos de entenderlo a través de los dos ejemplos.
Ejemplo 1
En días anteriores, las aplicaciones solían generar indicaciones de comando para aceptar entradas de usuario una tras otra. Hoy en día, los marcos de la interfaz de usuario crean instancias de varios elementos de la interfaz de usuario, recorren varios eventos de esos elementos de la interfaz de usuario (como pasar el mouse, hacer clic, etc.) y los programas de usuario / principal proporcionan ganchos (por ejemplo, oyentes de eventos de la interfaz de usuario en Java) para escuchar esos eventos. Por lo tanto, el "control" del flujo de elementos de la interfaz de usuario principal se mueve del programa de usuario al marco de la interfaz de usuario. En días anteriores, estaba en el programa de usuario.
Ejemplo 2
Considere la clase a CustomerProcessor
continuación:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Si quiero processCustomer()
ser independiente de cualquier implementación getAllCusts()
, no solo de la proporcionada por SqlCustRepo
, tendré que deshacerme de la línea: SqlCustRepo custRepo = new SqlCustRepo()
y reemplazarla con algo más genérico, capaz de aceptar un tipo variado de implementación, de modo que processCustomers()
simplemente funcione para cualquier implementación provista. El código anterior (instanciando la clase requerida SqlCustRepo
por la lógica del programa principal) es una forma tradicional y no logra este objetivo de desacoplarse processCustomers()
de la implementación de getAllCusts()
. En la inversión de control, el contenedor crea una instancia de la clase de implementación requerida (como se especifica por, digamos, la configuración xml), la inyecta en la lógica principal del programa que se enlaza según los ganchos especificados (por ejemplo, por @Autowired
anotación o getBean()
método en Spring Framework).
Veamos cómo se puede hacer esto. Considere el siguiente código.
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");
}
}
También podemos tener
class GraphCustRepo implements ICustRepo { ... }
y
<bean id="custRepo" class="GraphCustRepo">
y no necesitaremos cambiar App.java.
Por encima del contenedor (que es el marco de Spring) tiene la responsabilidad de escanear el archivo xml, instanciar el bean de tipo específico e inyectarlo en el programa del usuario. El programa de usuario no tiene control sobre qué clase se instancia.
PD: IoC es un concepto genérico y se logra de muchas maneras. Los ejemplos anteriores lo logran mediante inyección de dependencia.
Referencia: artículo de Martin Fowler .