Need for Dependency Injection

Let us understand why do we need Dependency Injection


As we all learned that DI is required since it provides loose coupling.

Let’s see how this is needed in some scenarios by considering the below requirement

Requirement :

Client need to open the door, whenever it opens he wants the alarm to be activated,and whenever he closes the door he wants alarm to be deactivated.

Create Door.java

  1. package com.kb.di;
  2.  
  3. public class Door {
  4.    
  5.     public void open()
  6.     {
  7.     }
  8.     public void close()
  9.     {
  10.  
  11.     }
  12. }
package com.kb.di;

public class Door {
    
    public void open()
    {
    }
    public void close()
    {

    }
}


Now I need to add Alarm functionality to the Door class

Create Alarm.java – Here I am using sound alarm feature.

  1. package com.kb.di;
  2.  
  3. public class SoundAlarm {
  4.     public SoundAlarm() {
  5.         System.out.println("SoundAlarm()");
  6.     }
  7.  
  8.     public void activate() {
  9.         System.out.println("SoundAlarm activated");
  10.     }
  11.  
  12.     public void deactivate() {
  13.         System.out.println("SoundAlarm deactivated");
  14.     }
  15. }
package com.kb.di;

public class SoundAlarm {
	public SoundAlarm() {
		System.out.println("SoundAlarm()");
	}

	public void activate() {
		System.out.println("SoundAlarm activated");
	}

	public void deactivate() {
		System.out.println("SoundAlarm deactivated");
	}
}


To provide this feature to Door class , I need use ‘has a‘ relationship also called as composition.

Modified Door class is as below

  1. package com.kb.di;
  2.  
  3. public class Door {
  4. private SoundAlarm alarm=new SoundAlarm();
  5.    
  6.      public void open(){
  7.         alarm.activate();
  8.     }
  9.     public void close()
  10.     {
  11.         alarm.deactivate();
  12.     }
  13. }
package com.kb.di;

public class Door {
private SoundAlarm alarm=new SoundAlarm();
    
     public void open(){
        alarm.activate();
    }
    public void close()
    {
        alarm.deactivate();
    }
}


Main client program(DIDemo)

  1. package com.kb.di;
  2.  
  3. public class DIDemo {
  4.     public static void main(String[] args) {
  5.         Door d = new Door();
  6.         d.open();
  7.         d.close();
  8.     }
  9.  
  10. }
package com.kb.di;

public class DIDemo {
	public static void main(String[] args) {
		Door d = new Door();
		d.open();
		d.close();
	}

}


Output

Now we finished our requirement of implementing the Alarm feature to Door class.

New Requirement

Now client requirement has been changed and they want Visual Alarm feature for Door class instead of sound alarm.

How can we achieve it ?


Create VisualAlarm class to have its functionality

  1. package com.kb.di;
  2.  
  3. public class VisualAlarm {
  4.     public VisualAlarm() {
  5.         System.out.println("VisualAlarm()");
  6.     }
  7.  
  8.     public void activate() {
  9.         System.out.println("VisualAlarm activated");
  10.     }
  11.  
  12.     public void deactivate() {
  13.         System.out.println("VisualAlarm deactivated");
  14.     }
  15. }
package com.kb.di;

public class VisualAlarm {
	public VisualAlarm() {
		System.out.println("VisualAlarm()");
	}

	public void activate() {
		System.out.println("VisualAlarm activated");
	}

	public void deactivate() {
		System.out.println("VisualAlarm deactivated");
	}
}


Approach 1

Modify the Door class by adding VisualAlarm class variable as below

  1. package com.kb.di;
  2.  
  3. public class Door {
  4. //private SoundAlarm alarm=new SoundAlarm();
  5.    
  6.  private VisualAlarm alarm=new VisualAlarm();
  7.    
  8.    
  9.     public void open()
  10.     {
  11.         alarm.activate();
  12.     }
  13.     public void close()
  14.     {
  15.         alarm.deactivate();
  16.     }
  17. }
package com.kb.di;

public class Door {
//private SoundAlarm alarm=new SoundAlarm();
	
 private VisualAlarm alarm=new VisualAlarm();
   
    
    public void open()
    {
        alarm.activate();
    }
    public void close()
    {
        alarm.deactivate();
    }
}

Now run DIDemo.java

  1. package com.kb.di;
  2.  
  3. public class DIDemo {
  4.     public static void main(String[] args) {
  5.         Door d = new Door();
  6.         d.open();
  7.         d.close();
  8.     }
  9.  
  10. }
package com.kb.di;

public class DIDemo {
	public static void main(String[] args) {
		Door d = new Door();
		d.open();
		d.close();
	}

}


Output

We have achived client’s new modification as well but where did we change ?

Door classyes we did a change in Door class.

Now again if client comes with sound alarm feature, we need to change our Door class.

So how to avoid this change in our domain class ?

Factory pattern, Yes lets try with Factory pattern

Create a factory which produces the alarm and we name it as Alarm Factory.

Create an interface Alarm and make SoundAlarm ,VisualAlarm class to implement this Alarm interface.

We are doing this to achive Program To Supertype not concrete type(Also called Program to Interface)

Create Alarm Interface

  1. package com.kb.di;
  2.  
  3. public interface Alarm {
  4.     public void activate();
  5.     public void deactivate();
  6. }
package com.kb.di;

public interface Alarm {
	public void activate();
	public void deactivate();
}


Create SoundAlarm class

  1. package com.kb.di;
  2.  
  3. public class SoundAlarm implements Alarm  {
  4.     public SoundAlarm() {
  5.         System.out.println("SoundAlarm()");
  6.     }
  7.  
  8.     public void activate() {
  9.         System.out.println("SoundAlarm activated");
  10.     }
  11.  
  12.     public void deactivate() {
  13.         System.out.println("SoundAlarm deactivated");
  14.     }
  15. }
package com.kb.di;

public class SoundAlarm implements Alarm  {
	public SoundAlarm() {
		System.out.println("SoundAlarm()");
	}

	public void activate() {
		System.out.println("SoundAlarm activated");
	}

	public void deactivate() {
		System.out.println("SoundAlarm deactivated");
	}
}


Create VisualAlarm class

  1. package com.kb.di;
  2.  
  3. public class VisualAlarm implements Alarm{
  4.     public VisualAlarm() {
  5.         System.out.println("VisualAlarm()");
  6.     }
  7.  
  8.     public void activate() {
  9.         System.out.println("VisualAlarm activated");
  10.     }
  11.  
  12.     public void deactivate() {
  13.         System.out.println("VisualAlarm deactivated");
  14.     }
  15. }
package com.kb.di;

public class VisualAlarm implements Alarm{
	public VisualAlarm() {
		System.out.println("VisualAlarm()");
	}

	public void activate() {
		System.out.println("VisualAlarm activated");
	}

	public void deactivate() {
		System.out.println("VisualAlarm deactivated");
	}
}


Create Alarm Factory

  1. package com.kb.di;
  2.  
  3. public class AlarmFactory {
  4. public Alarm getRequiredAlarm(){
  5.     return new VisualAlarm();
  6. }
  7. }
package com.kb.di;

public class AlarmFactory {
public Alarm getRequiredAlarm(){
	return new VisualAlarm();
}
}


Create Door class

  1. package com.kb.di;
  2.  
  3. public class Door {
  4.    
  5.   private Alarm alarm = new AlarmFactory().getRequiredAlarm();
  6.    
  7.    
  8.     public void open()
  9.     {
  10.         alarm.activate();
  11.     }
  12.     public void close()
  13.     {
  14.         alarm.deactivate();
  15.     }
  16. }
package com.kb.di;

public class Door {
	
  private Alarm alarm = new AlarmFactory().getRequiredAlarm();
   
    
    public void open()
    {
        alarm.activate();
    }
    public void close()
    {
        alarm.deactivate();
    }
}


Door class gets the Visual alarm from factory.

To change it to sound alarm feature. we need not to modify the Door class but we need to modify the Factory to return sound alarm as below

  1. package com.kb.di;
  2.  
  3. public class AlarmFactory {
  4. public Alarm getRequiredAlarm(){
  5.     return new SoundAlarm();
  6. }
  7. }
package com.kb.di;

public class AlarmFactory {
public Alarm getRequiredAlarm(){
	return new SoundAlarm();
}
}

So ultimately change is required in Java class but this time it is factory class instead of Door class.

So how to avoid this change in Java class completely ?

Not possible unless and until we use Spring’s Dependency Injection.

Lets achive it using Spring’s DI in a very simple way


Step 1. Create Alarm Interface – same as above

Step 2. Create VisualAlarm class – same as above

Step 3. Create SoundAlarm class – same as above

Step 4. Create Door class – need to modify to add Alarm reference and its getter, setter as below

  1. package com.kb.di;
  2.  
  3. public class Door {
  4.  
  5.     private Alarm alarm;
  6.  
  7.     public void open() {
  8.         alarm.activate();
  9.     }
  10.  
  11.     public void close() {
  12.         alarm.deactivate();
  13.     }
  14.  
  15.     public Alarm getAlarm() {
  16.         return alarm;
  17.     }
  18.  
  19.     public void setAlarm(Alarm alarm) {
  20.         this.alarm = alarm;
  21.     }
  22. }
package com.kb.di;

public class Door {

	private Alarm alarm;

	public void open() {
		alarm.activate();
	}

	public void close() {
		alarm.deactivate();
	}

	public Alarm getAlarm() {
		return alarm;
	}

	public void setAlarm(Alarm alarm) {
		this.alarm = alarm;
	}
}


Step 5. Create spring config file

  1. <?xml version="1.0" encoding="UTF-8"?>
  2.  
  3. <beans xmlns="http://www.springframework.org/schema/beans"
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.     xmlns:context="http://www.springframework.org/schema/context"
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans
  7.    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8.    http://www.springframework.org/schema/context
  9.    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  10.  
  11.     <bean id = "door" class ="com.kb.di.Door">
  12.           <property name="alarm" ref="soundAlarm"/>    
  13.     </bean>
  14.     <bean id="soundAlarm" class="com.kb.di.SoundAlarm"/>
  15.     <bean id="visualAlarm" class="com.kb.di.VisualAlarm"/>
  16.  
  17. </beans>
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id = "door" class ="com.kb.di.Door">
          <property name="alarm" ref="soundAlarm"/>    
    </bean>
    <bean id="soundAlarm" class="com.kb.di.SoundAlarm"/>
    <bean id="visualAlarm" class="com.kb.di.VisualAlarm"/>

</beans> 


Step 6. Create a client program

  1. package com.kb.di;
  2.  
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5.  
  6. public class DIDemo {
  7.     public static void main(String[] args) {
  8.         ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  9.         Door d = context.getBean("door",Door.class);
  10.         d.open();
  11.         d.close();
  12.     }
  13.  
  14. }
package com.kb.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DIDemo {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		Door d = context.getBean("door",Door.class);
		d.open();
		d.close();
	}

}


Now if client wants the feature of visual alarm, no need of changing any java class, we can achive it just by changing the xml file as below

  1. <?xml version="1.0" encoding="UTF-8"?>
  2.  
  3. <beans xmlns="http://www.springframework.org/schema/beans"
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.     xmlns:context="http://www.springframework.org/schema/context"
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans
  7.    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  8.    http://www.springframework.org/schema/context
  9.    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  10.  
  11.     <bean id = "door" class ="com.kb.di.Door">
  12.         <property name="alarm" ref="visualAlarm"/>    
  13.     </bean>
  14.     <bean id="soundAlarm" class="com.kb.di.SoundAlarm"/>
  15.     <bean id="visualAlarm" class="com.kb.di.VisualAlarm"/>
  16.  
  17. </beans>
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <bean id = "door" class ="com.kb.di.Door">
        <property name="alarm" ref="visualAlarm"/>    
    </bean>
    <bean id="soundAlarm" class="com.kb.di.SoundAlarm"/>
    <bean id="visualAlarm" class="com.kb.di.VisualAlarm"/>

</beans>


Now new feature has been added without changing any java class.

Spring injects dependent object using our xml configuration, so we can add corresponding bean for our client based on their requirement.

About the Author

Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on