he Inversion of Control (IoC) pattern, also known as Dependency Injection, has recently become popular in the J2EE community. Several open source projects, including Spring, PicoContainer, and HiveMind, use the IoC pattern to develop lightweight J2EE Containers.
IoC is not a new concept, however. It has been around for several years now. Using object-oriented design principles and features such as interface, inheritance, and polymorphism, the IoC pattern enables better software design that facilitates reuse, loose coupling, and easy testing of software components. This article discusses IoC and demonstrates how to use this pattern in your software design without having to implement any of the open source frameworks.
IoC Design Pattern
Assume Class A has a relationship with Class B: it wants to use the services of Class B. The usual way to establish this relationship is to instantiate Class B inside Class A. Though this approach works, it creates tight coupling between the classes. You can't easily change Class B without modifying Class A. To eliminate the coupling, you can have a Configurator inject the instance of Class B (Object "b") to the instance of Class A (Object "a"). If you want to change the implementation of Class B later on, you simply change the Configurator object. So, the control of how Object "a" gets the reference of Object "b" is inverted. Object "a" is not responsible for getting the reference to Object "b". Instead, the Configurator is responsible for it. This is the basis for the IoC design pattern.
![](http://www.devx.com/assets/articlefigs/12520.gif) | |
Figure 1. Object "a" Directly Creates Object "b" |
To demonstrate the benefits of the Configurator object in this case, the following examples show a simple design without IoC and one with IoC (click here to download the sample code for this article).
Listing 1 and Figure 1 are simple examples in which Class A uses Class B:
public class A{
private B b;
public A(){
b=new B();
}
Listing 1. Class A Directly Refers Class B
Listing 1 assumes the following design decisions:
- Class A needs a reference to Class B.
- Class B is a concrete class that has a default constructor.
- Class A owns the instance of class B.
- No other class can access the instance of Class B.
![](http://www.devx.com/assets/articlefigs/12521.gif) | |
Figure 2. Object "a" First Creates Object "c" and Then Object "b" by Passing Object "c" |
If any one of the above design decisions change, then the code in Listing 1 must be modified. For example, if Class B changed to have a non-default constructor, which takes Class C (see Figure 2), then Listing 1 would change to Listing 2.
public class A{
private B b;
public A(){
C c=new C();
b=new B(c);
}
Listing 2. Class A Directly Refers Class B and Class C
Once again, Listing 2 assumes certain design decisions. Now Object "a" owns both Object "b" and Object "c". If Class B or Class C changes at all, then Class A needs to change as well. In essence, a simple design of a simple class with implicit design assumptions becomes a maintenance nightmare in the future. Consider how difficult making changes would be if you had this scenario in a typical application with several classes.
Alternatively, if you use a framework that uses the IoC pattern, the responsibility of creating Object "b" moves from Object "a" to the IoC framework, which creates and injects Object "b" into Object "a". This insulates Class A from the changes in Class B. Before Object "a" is used, it needs the reference to Object "b". The IoC framework will inject Object "b" into Object "a".
![](http://www.devx.com/assets/articlefigs/12522.gif) | |
Figure 3. IoC Framework Creates Object "b" and Sets It to Object "a" |
Listing 3 shows Class A from the previous listings modified to use the IoC pattern.
public class A{
private B b;
public A(){
}
public setB(B b){
this.b=b;
}
}
Listing 3. Class A Gets the Reference to Class B via setB
Listing 3 assumes the following design decisions:
- A needs a reference to B, and it doesn't need to know how B is instantiated.
- B can be an interface, an abstract class, or a concrete class.
- Before the instance of Class A is used, it needs a reference to the instance of Class B.
From the above design decisions, you can see that there is no tight coupling between Class A and Class B. Both can be changed independently without affecting each other. Of course, if there is any change in the public methods of Class B, Class A needs to change as well. But how Object "b" is created and managed is not decided in the implementation of Object "a". Instead, the IoC framework uses the setB() method in Object "a" to inject Object "b" (see Figure 3).
|