Monday, May 2, 2011

Dependency injection [ Part 1]


Dependency Injection (DI)



Dependency Injection is concrete implementation of Inversion of Controls (IOC).  Inversion of Controls is an abstract principle whereas DI is a real implementation of IOC. Like Object Oriented paradigm deals with inheritance, polymorphism, encapsulation, abstraction whereas Java and .Net is an object oriented programming language which implements Object Oriented concepts.
Dependency describes the dependability of the object whereas injection is a mechanism to supply such dependency by injecting appropriate dependent object during object creation time.

What is dependency?

Let’s try to understand what you mean by dependency.

Code snippet 1

/**
 * @author Ashish.Chudasama
 */
package com.novice.traveler;

import com.novice.vehicle.Bus;

public class Traveler {

      // highly coupling between declaration and initialization of object. 
      Bus vehicle = new Bus();
      // start journey
      public void travel() {
            vehicle.move();
      }
      // Journey simulator...
      public static void main(String[] args) {
            new Traveler().travel();
      }

}
Output :
Move..task
Key points
1)      Code snippet 1 shows the traveler class depends on instance of bus class. We called Traveler class is dependent on Bus instance because Traveler class delegates travel responsibility to the Bus instance to move.
2)      If dependency initialization moves to Constructor, still Traveler class directly aware the Bus class dependency.

3)      The dependency can be supply to the Traveler class using Look-up mechanism.

4)      Look-up mechanism injects the Bus instance to the Traveler class, but class is still restricted to only Bus type and sub-type of Bus only.
5)      Traveler class has strong coupling with Bus instance because variable declaration and variable initialization restricted to Bus reference.


6)      Traveler class shows the tight coupling with Bus class, because of that if tomorrow Traveler class requires Car class instead of Bus class then code modification is required.

Code improvement


Reduce instance specific coupling with the help of run time polymorphism. Use the super class reference to access the specific implementation of derived class instance.

 

Code snippet 2

/**
 * @author Ashish.Chudasama
 */
package com.novice.traveler;

import com.ninja.vehicle.Bus;
import com.ninja.vehicle.Vehicle;

public class TravelerImprove {

      // loose coupling between declaration
      // and initialization of object with
// safe type reference.
      Vehicle vehicle = new Bus();

      // start journey
      public void travel() {
            vehicle.move();
      }
      // Journey simulator...
      public static void main(String[] args) {
            new TravelerImprove().travel();
      }

}



It is necessary to understand the aggregation and composition terminology which has direct impact of coding.

Aggregation

Composition



Represent  "has-a" or "whole/part" relationship
Represent  "has-a” or  "whole/part" relationship
Lifespan of object represent “has-a” relationship may or may not be depend on lifespan of outer class i.e. Lifespan of Vehicle is not dependent on lifespan of Traveler class instance.
Lifespan of object represent of “Has-a” relationship is directly dependent on lifespan of outer class i.e. lifespan of vehicle is directly depend on lifespan of traveler class instance.
Has-A relationship shows the dependency but this dependency does not created using new operator or class.forName method.
Created using new or class.forName method
Traveler class is not responsible for the creation and destruction of Bus instance. Hence instance of Bus exists without instance of Traveler.
Traveler class is responsible for the creation and destruction of Bus instance. Hence instance of Bus cannot be exists without instance of Traveler.


UML  notation

UML  notation


Spring Framework & DI


Spring framework support dependency injection features to decouple the dependency from the source code /class to external files or uses the annotation to represent the dependency.
Quick overview
1)      It is an open source framework.
2)      It is an IOC container which supports dependency injection to express object dependency in a declarative format with the help of xml configuration file. Now spring supports annotation base dependency injection too.
3)      Spring framework is a container means it is responsible for managing life cycle of objects created by the framework based on configuration.
4)      It is developer friendly framework which can be used for small scale to large scale application.
5)      It is one of the trusted and widely uses framework for the JEE development.
6)      Spring manage all object as a Java Bean.  Spring core supports singleton and prototype scope and default scope is singleton.

Let’s configure spring framework for the Traveler class whose class diagram as below


Code snippet 3


Traveler class declares the vehicle reference which will be injected into the Traveler class when instance of traveler class is requested to the spring framework.
package com.ninja.vehicle;
/**
 * @author Ashish.Chudasama
 */
public class Traveler {

      Vehicle vehicle = null;
      //setter injection for the Vehicle dependency
      public void setVehicle(Vehicle vehicle) {
            this.vehicle = vehicle;
      }
      // start journey
      public void travel() {
            vehicle.move();
      }
     
}

Code snippet 4


Vehicle class depends on Tier. Vehicle class delegates its move responsibility to rotate method of wheel implementer class.
package com.ninja.vehicle;
/**
 * @author Ashish.Chudasama
 */
public interface Vehicle {
      void move();
}

Code snippet 5


Bus is a concrete implementation of Vehicle. Bus class depends on Wheel and delegates its move task to rotate method of the wheel implementer sub-classes.
/**
 * @author Ashish.Chudasama
 */
package com.ninja.vehicle;

import com.novice.vehicle.component.Wheel;

public class Bus implements Vehicle {
      //Wheel is dependency of Vehicle to move
      Wheel wheel;
     
      // setter based dependency
      public void setWheel(Wheel wheel) {
            this.wheel = wheel;
      }

      @Override
      public void move() {
System.out.println(this.getClass().getSimpleName());
            wheel.rotate();
      }
}

 

Code snippet 6

Car is a concrete implementation of Vehicle. Car class depends on Wheel and delegates its move task to rotate method of the wheel implementer sub-classes.
/**
 * @author Ashish.Chudasama
 */
package com.ninja.vehicle;

import com.novice.vehicle.component.Wheel;

public class Car implements Vehicle {

      //Wheel is dependency of Vehicle to move
      Wheel wheel;
     
      // setter based dependency
      public void setWheel(Wheel wheel) {
            this.wheel = wheel;
      }

      @Override
      public void move() {
System.out.println(this.getClass().getSimpleName());
            wheel.rotate();
      }
}

Code snippet 7


A wheel class delegate is rotation function to actual Tier implementer classes to perform task of rotation.
package com.novice.vehicle.component;

/**
 * @author Ashish.Chudasama
 */
public class Wheel {

      //Tire is dependency of wheel class
      Tire tire=null;

      //Supply dependency using setter
      public void setTire(Tire tire) {
            this.tire = tire;
      }
     
      //function of wheel class
      public void rotate()
      {
            tire.rotate();
      }
}

Code snippet 8


Tire is an interface which ensures that all sub-classes or implementer of Tire can perform the task of rotation.
package com.novice.vehicle.component;

/**
 * @author Ashish.Chudasama
 */
public interface Tire {
      void rotate();
}

Code snippet 9


MRFTire is a concrete implementation of Tier interface.
package com.novice.vehicle.component;

/**
 * @author Ashish.Chudasama
 */
public class MRFTire implements Tire {
      @Override
      public void rotate() {
System.out.println(this.getClass().getSimpleName());
            System.out.println("Actual Work… (rotating tire)");
      }

}

Code snippet 10


JKTire is a concrete implementation of Tier interface.
package com.novice.vehicle.component;

/**
 * @author Ashish.Chudasama
 */
public class JKTire implements Tire {
      @Override
      public void rotate() {
            System.out.println(this.getClass().getSimpleName());
            System.out.println("Actual Work… (rotating tire)");
      }

}

Code snippet 11


This is test stub to check the spring dependency injection.

package com.ninja.vehicle;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Ashish.Chudasama
 */
public class TestSpringDI {

      public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                        "springconfig.xml");
            BeanFactory factory = context;
            Traveler test = (Traveler) factory.getBean("traveler");
            test.travel();
      }

}

Code snippet 12


Spring configuration file
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
<!-- Tire bean declaration -->
      <bean id="mrfTire" class="com.novice.vehicle.component.MRFTire" />
      <bean id="jkTire" class="com.novice.vehicle.component.JKTire" />

      <!-- Wheel bean declaration -->
      <bean id="wheel" class="com.novice.vehicle.component.Wheel">
            <property name="tire" ref="mrfTire" />
            <!-- wheel uses the MRFTire this can be easily
             replaceable by changing bean reference to jkTire  bean  -->
      </bean>

      <!-- Vehicle bean declaration -->
      <bean id="car" class="com.ninja.vehicle.Car">
            <property name="wheel" ref="wheel" />
      </bean>

      <bean id="bus" class="com.ninja.vehicle.Bus">
            <property name="wheel" ref="wheel" />
      </bean>

      <!-- Traveler bean declaration -->
      <bean id="traveler" class="com.ninja.vehicle.Traveler">
            <property name="vehicle" ref="car" />
            <!-- change car reference to bus bean reference to check the
            dependency injection and easy way to manage the dependency -->
      </bean>


</beans>

Output
Car
Wheel
MRFTire
Actual Work… (Rotating tire)

Modify traveler bean definition as highlighted in code snippet
<!-- Traveler bean declaration -->
      <bean id="traveler" class="com.ninja.vehicle.Traveler">
            <property name="vehicle" ref="bus" />
            <!-- change car reference to bus bean reference to check the
            dependency injection and easy way to manage the dependency -->
      </bean>

Output
Bus
MRFTire
Actual Work… (Rotating tire)

Modify wheel bean definition as highlighted in code snippet
<!-- Wheel bean declaration -->
      <bean id="wheel" class="com.novice.vehicle.component.Wheel">
            <property name="tire" ref="jkTire" />
            <!-- wheel uses the MRFTire this can be easily
             replaceable by changing bean reference to jkTire  bean  -->
      </bean>
Output
Bus
JKTire
Actual Work… (Rotating tire)




Click here to download source code.

7 comments:

  1. ------------------------------------------------------------------
    Consolidated comments from Linekd in
    http://www.linkedin.com/groupAnswers?viewQuestionAndAnswers=&discussionID=52453044&gid=70526&commentID=38073762&trk=view_disc
    ------------------------------------------------------------------

    Adrián Córdoba • Thanks Ashish!
    This article is very useful for me.
    I'm waitting for the second part.

    ------------------------------------------------------------------


    Janardhan Chejarla • Nice guide about IOC

    ReplyDelete
  2. ------------------------------------------------------------------ linkedin -------------------------------------
    Oleg Vakulski


    In a practical way, Dependency Injection concept covers all aprroaches to simplification of interaction between Client and Services, delegates responsibility for service details to special part of code.
    If Service changes, only relativele small part of code should be redesigned. Simple and effective solution.

    ReplyDelete
  3. ----------------------------------- linkedin -------------------------------

    Vincenzo Guastella • Why reinventing the wheel ?

    What you are struggling to explain has been already documented and clearly exposed years ago.

    http://martinfowler.com/articles/injection.html

    ----------------------------------------------------------------------------

    Dennis Chacko • Not sure if he was attempting to "reinvent" anything, just as the numerous other articles on the internet explaining dependency injection do not claim to "invent" the pattern.
    Sometimes its good to read other people's explanation or description of certain concepts rather than having just one description.

    ReplyDelete
  4. Nice article Ashish. Simple and elegant. Keep up the good work

    ReplyDelete
  5. Nice article, I truly appreciate it. Its time to give back to this world, and u r doing it...
    Thanks Ashish!

    ReplyDelete