Let us try to understand it through the two examples.
Example 1
In earlier days, apps used to generate command prompts to accept user inputs one after other. Today, UI frameworks instantiates various UI elements, loop through various events of those UI elements (like mouse hover, click etc.) and user/main programs provides hooks (for example UI event listeners in Java) for listening to those events. So the main UI element flow "control" is moved from user program to UI framework. In earlier days, it was in user program.
Example 2
Consider class CustomerProcessor
below:
class CustomerProcessor
{
SqlCustRepo custRepo = new SqlCustRepo();
private void processCustomers()
{
Customers[] custs = custRepo.getAllCusts();
}
}
If I want processCustomer()
to be independent of any implementation of getAllCusts()
, not just the one provided by SqlCustRepo
, I will need to get rid of line: SqlCustRepo custRepo = new SqlCustRepo()
and replace it with something more generic, capable of accepting varied type of implementation, such that the processCustomers()
will simply work for any provided implementation.
Above code (instantiating required class SqlCustRepo
by main program logic) is a traditional way and it does not achieves this goal of decoupling processCustomers()
from implementation of getAllCusts()
. In inversion of control, the container instantiates the required implementation class (as specified by, say xml configuration), injects it in the main program logic which gets bound as per hooks specified (say by @Autowired
annotation or getBean()
method in spring framework).
Lets see how this can be done. Consider below code.
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");
}
}
We can also have
class GraphCustRepo implements ICustRepo { ... }
and
<bean id="custRepo" class="GraphCustRepo">
and we will not need to change App.java.
Above the container (which is the spring framework) has the responsibility to scan xml file, instantiate the bean of specific type and inject it into the user program. User program have no control on which class is instantiated.
PS: IoC is generic concept and is achieved in many ways. Above examples achieves it by dependency injection.
Reference: Martin Fowler's article.