Inversion of Control, also called as dependency Injection, is all about inverting the control. Or, how one object uses another object. Suppose class A wants to use class B. Traditionally, you would create and use an instance of class B within class A, like in the following example:
Class A {
private B b;
public A() {
b = new B();
}
public void doSomething(){
b.someMethod();
}
}
This approach has following problems:
- The creation of object B relies upon the availability of a default constructor.
- Any change in the constructor implementation of class B will necessitate a change in the implementation of class A.
- Suppose class A wants to use class C instead of class B. Then class A needs to change. What happens if class B and class C are two separate implementations of same service and the application will need to switch over from one implementation to the other?
All three of the problems in the code example are due the strong coupling of class A and class B. Class A first needs to know that it must use an instance of class B and then it needs to know how to construct an instance of class B.
The solution to this problem is to eliminate the dependency from class A. What follows is a modified class A, where strong coupling is removed:
Class A {
private B b;
public A(B b) {
this.b = b;
}
public void doSomething(){
b.someMethod();
}
}
This example accepts an instance of class B via the constructor. This relieves class A from knowing how to instantiate class B. Now, in order to use class A, the caller class of A must also instantiate class B and pass it into class A. In this context, the caller class is also acting as an assembler of object A and object B. Object A does not explicitly look for B, but B is supplied to it. This is the Inversion of Control. The control of class B is taken out of class A and placed in the Assembler class.
IoC Frameworks
Several open source IoC frameworks like Spring, PicoContainer, and HiveMind support the IoC pattern. While the general IoC principle is simple, each of these frameworks supports different implementations and offers different benefits. The IoC pattern can be implemented in three ways: setter based, constructor based, and interface based.
Setter-Based IoC
This type of IoC uses a setter method to inject the referenced object into a referring object. This is the most common type of IoC, and both Spring and PicoContainer implement it. Setter-based IoC is good for objects that take optional parameters and objects that need to change their properties many times during their lifecycles. Its main disadvantage is that you need to expose all the properties of an object to the outside world when using a setter method. This breaks one of the key OO principles: data encapsulation and information hiding.
Constructor-Based IoC
This type of IoC uses a constructor to set the reference of the object. Its main advantage is that only the creator knows about the referenced object. Once the object is created, the client code that uses the object is unaware of the referenced object. This approach may not work in all types of applications, however. For example, if you use an external API that needs a default constructor, then you need to go with a setter-based IoC. A constructor-based IoC is the main type of implementation in Spring.
Interface-Based IoC
In this type of IoC, objects implement a specific interface from the IoC framework, which the IoC framework will use to properly inject the objects. One of the main advantages of this type is that it doesn’t need an external configuration file to configure the object references. Since you need to use the IoC framework’s marker interface, the IoC framework knows how to glue the objects together. It is similar to using EJB. Any EJB container knows how to instantiate your objects and hook them with itself. The main
disadvantage of this approach is that the marker interface ties your application to a specific IoC framework. Apache Avalon is based on this approach but this project has been closed.