Proviamo a capirlo attraverso i due esempi.
Esempio 1
Nei giorni precedenti, le app utilizzate per generare prompt dei comandi per accettare gli input dell'utente uno dopo l'altro. Oggi, i framework dell'interfaccia utente istanziano vari elementi dell'interfaccia utente, eseguono il ciclo attraverso vari eventi di quegli elementi dell'interfaccia utente (come passaggio del mouse, clic, ecc.) E i programmi utente / principale forniscono hook (ad esempio i listener di eventi dell'interfaccia utente in Java) per l'ascolto di quegli eventi. Quindi il "controllo" del flusso dell'elemento dell'interfaccia utente principale viene spostato dal programma utente al framework dell'interfaccia utente. Nei giorni precedenti, era nel programma utente.
Esempio 2
Valuta la classe CustomerProcessor
seguente:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
Se voglio processCustomer()
essere indipendente da qualsiasi implementazione getAllCusts()
, non solo da quella fornita SqlCustRepo
, dovrò liberarmi della linea: SqlCustRepo custRepo = new SqlCustRepo()
e sostituirla con qualcosa di più generico, in grado di accettare vari tipi di implementazione, in modo tale che processCustomers()
funzionerà semplicemente per qualsiasi implementazione fornita. Il codice sopra (istanza della classe richiesta SqlCustRepo
dalla logica del programma principale) è un modo tradizionale e non raggiunge questo obiettivo di disaccoppiamento processCustomers()
dall'implementazione di getAllCusts()
. Nell'inversione del controllo, il contenitore crea un'istanza della classe di implementazione richiesta (come specificato da, diciamo configurazione xml), la inietta nella logica del programma principale che viene vincolata come da hook specificati (diciamo per @Autowired
annotazione o getBean()
metodo nel framework di primavera).
Vediamo come si può fare. Considerare sotto il codice.
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: l'IoC è un concetto generico ed è realizzato in molti modi. Gli esempi sopra riportati lo ottengono mediante iniezione di dipendenza.
Riferimento: articolo di Martin Fowler .