Cerchiamo di capirlo attraverso i due esempi.
Esempio 1
Nei giorni precedenti, le app utilizzate per generare comandi chiedevano di accettare gli input dell'utente uno dopo l'altro. Oggi, i framework dell'interfaccia utente istanziano vari elementi dell'interfaccia utente, eseguono il ciclo di vari eventi di tali elementi dell'interfaccia utente (come mouse hover, clic ecc.) E i programmi utente / principale forniscono hook (ad esempio ascoltatori di eventi UI in Java) per l'ascolto di tali eventi. Quindi il "controllo" del flusso di elementi dell'interfaccia utente viene spostato dal programma utente al framework dell'interfaccia utente. Nei giorni precedenti era nel programma utente.
Esempio 2
Considera la classe CustomerProcessor
di seguito:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Se voglio che processCustomer()
sia indipendente da qualsiasi implementazione di getAllCusts()
, non solo quella fornita da SqlCustRepo
, dovrò eliminare la riga: SqlCustRepo custRepo = new SqlCustRepo()
e sostituirla con qualcosa di più generico, in grado di accettare vari tipi di implementazione, in modo tale che processCustomers()
funzioni semplicemente per qualsiasi implementazione fornita.
Il codice sopra (istanza richiesta classe SqlCustRepo
dalla logica del programma principale) è un modo tradizionale e non raggiunge questo obiettivo di disaccoppiamento processCustomers()
dall'implementazione di getAllCusts()
. In inversione di controllo, il contenitore crea un'istanza della classe di implementazione richiesta (come specificato dalla configurazione xml), la inietta nella logica del programma principale che viene associata come per gli hook specificati (ad esempio dal metodo @Autowired
o getBean()
in primavera quadro).
Vediamo come questo può essere fatto. Considera il codice seguente.
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");
}
}
Possiamo anche avere
class GraphCustRepo implements ICustRepo { ... }
e
<bean id="custRepo" class="GraphCustRepo">
e non avremo bisogno di cambiare App.java.
Sopra il contenitore (che è il framework di primavera) ha la responsabilità di scansionare il file xml, creare un'istanza del bean di tipo specifico e iniettarlo nel programma utente. Il programma utente non ha alcun controllo su quale classe viene istanziata.
PS: IoC è un concetto generico ed è raggiunto in molti modi. Gli esempi sopra lo raggiungono per iniezione di dipendenza.
Riferimento: articolo di Martin Fowler .