Why should we use dependency injection?

5 years ago by in Articles, Dependency Injection, Guice Tagged: , , ,

In this article, we will explore some of the benefits of dependency injection and how this can be used in all types of programming, including small and simple programs. Some of the example shown below make use of Guice (Homepage), a dependency injection framework by Google. The same concept applies for any other dependency injection framework such as Spring (Homepage).

Please note that this article does not provide detailed description of Guice or any other dependency injection framework, but it only focuses on the benefits of dependency injection and design methods that improve modularity, extendibility and testing. The main idea behind this article is to understand why dependency injection should be used rather than how to implement it.

All code listed below is available at: https://github.com/javacreed/why-should-we-use-dependency-injection. Most of the examples will not contain the whole code and may omit fragments which are not relevant to the example being discussed. The readers can download or view all code from the above link.

What is dependency injection?

Let say we want to make some tea. How would we do it and what do we need? We need some boiled water, a clean mug, teabags, sugar and milk (at least that’s what I put into mine). In order to make tea we need to provide all these ingredients and we need to manage all these ourselves. We have to fill the kettle with water and heat it up, get the milk from the refrigerator and get the rest.

Now assume that we can make tea, by simply asking someone else to do it for us. Someone that knows how to do the tea just the way we want it. Would that be better than making the tea ourselves? If yes, then welcome to dependency injection.

Dependency injection is a framework that takes care of creating objects for us without having to worry about providing the right ingredients so to say.

A Simple Example

Let say we have a class, Person, and this class needs to send a message. The Person class requires the aid of some other class, Email, in order to send a message. Following is a simple way of doing this.

package com.javacreed.examples.di.part1;

public class Email {
 public void sendEmail(String subject, String message){
   // Send the email
 }
}
package com.javacreed.examples.di.part1;

public class Person {
 private Email email = new Email();

 public void greetFriend(){
   email.sendEmail("Hello", "Hello my friend :)");
 }
}

We all agree that this is a very simple and straightforward example that involves two simple Java classes. Nevertheless, the above has some limitations as described below.

  • The Person class is dependent (has a strong/tight dependency) on the Email class. There is a hard connection between these two classes. Let say we have a new and better version of email class, FastEmail, in order for us to use it, we need to go in each and every class that depends on the Email class, such as the Person class, and replace it with the new version.
  • Let say we parameterise the Email‘s constructor. Again we have to go in each and every class that is initialising the Email class, such as the Person class, and change it.
  • A design decision is taken to make the Email class Singleton (Wiki). Similar to above we need to modify all instances where it is used.
  • In order to improve the notifications/messages system, we decide to add different message delivery systems such as SMS or tweets. The Person class and others like it, need to all be modified in order for it to use the new implementations.
  • Another developer needs to use the Person class, but would like to use a different notification/message system. This cannot be achieved with the current version of the Person class as it is hardwired to the Email class. What generally happens is that the other developer duplicates the Person class and modifies it as he/she needs. The projects ends up with two versions of the Person class.
  • In the above points we mentioned many scenarios where code has to be changed. All changes made, need to and should be tested. How can we test the Person class without including the message delivery class such as the Email? Testing, in many cases, is left as an afterthought. The way we have the Person class constructed makes it hard to test it without involving the Email class. Furthermore, how would we automate such test? How can we use JUnit (Homepage), or the like, to automate out tests?
  • Moving forward in the project, the Person class starts to depend on another class that allow this object to write a letter using the Pen class for example. The Person class can use other ways to write a letter, such as Pencil class or Typewriter class, but this approach does not allow that.

These limitations can be improved by changing the way we think and refactor our code in a modular way. This is independent from dependency injection and the dependency injection framework as we will see in the following section.

Change the way we think

The Email class provides a service, that is, sending of messages over the Internet using the mail protocol. Instead of having the Person class initialising an instance of the Email class, we first create an interface, MessageService, and make the Person class using this interface instead. This removes the dependency that the Person class has on the Email and replaces it with an abstract message delivery interface.

The following three steps: define, implement and use, show how we can develop modular and extendable code. This approach also improves testing as we will see at the end of this article.

  1. Define Interfaces

    Many developers do not use interfaces as they see them as additional, non-required, code. This may be true (I said maybe as the System class makes use of interfaces) for the famous hello world (example) program, definitely not true for the rest. Like with everything else, we have to see things in context and there will be cases when we can do without interfaces. Nevertheless, developing code using interfaces produce far more modular and extendable code as illustrated in the following examples. The example discussed in the previous section was quite simple, but it included several pitfalls which can be easily avoided by using interfaces instead of concrete classes to define services. Changing code at a later stage involves more work than having it right in the first place.

    We start by defining the MessageService interface that includes one method, sendMessage(String subject, String message). For simplicity we assume that no exceptions are thrown.

    package com.javacreed.examples.di.part2;
    
    public interface MessageService {
     void sendMessage(String subject, String message);
    }
    
  2. Implement Interfaces

    In the list of limitations we mentioned four possible methods of sending a message: email, fast email, SMS and tweet. Let’s create four classes that handle each message delivery method and have all these classes implement the interface created above.

    package com.javacreed.examples.di.part2;
    
    public class EmailService implements MessageService {
     @Override
     public void sendMessage(String subject, String message){
       System.out.printf("Email: %s, %s%n", subject, message);
     }
    }
    
    package com.javacreed.examples.di.part2;
    
    public class FastEmailService implements MessageService {
     @Override
     public void sendMessage(String subject, String message){
       System.out.printf("Fast Email: %s, %s%n", subject, message);
     }
    }
    
    package com.javacreed.examples.di.part2;
    
    public class SmsService implements MessageService {
     @Override
     public void sendMessage(String subject, String message){
       System.out.printf("SMS: %s, %s%n", subject, message);
     }
    }
    
    package com.javacreed.examples.di.part2;
    
    public class TweetService implements MessageService {
     @Override
     public void sendMessage(String subject, String message){
       System.out.printf("Tweet: %s, %s%n", subject, message);
     }
    }
    
  3. Use Interfaces

    Finally, instead of using classes, we use interfaces. In the Person class, we replace the Email field with the MessageService service interface as highlighted below.

    public class Person {
     private MessageService messageService;
    
     public Person(MessageService messageService){
       this.messageService = messageService;
     }
    
     public void greetFriend(){
       messageService.sendMessage("Hello", "Hello my friend :)");
     }
    }
    

    Note that the Person class is not initialising the message service but it is expecting it as a parameter of its constructor. This is a key element in the design. It improves modularity, extendibility and testing. The Person class is not dependent on any implementation, but on a service defined by an interface. This means that we can use the Person class without having to worry about the underlying implementation of the message service. Furthermore, different Person instances can be instantiated using different message services.

One can argue that the new version of Person class became more complex to instantiate as it requires parameters. This is a fair statement and here is when dependency injection comes into play.

Using Dependency Injection

As mentioned in the introduction, dependency injection can help us initialising objects and provide these objects all the necessary resources (ingredients). For example, the Person class requires an instance of MessageService. The dependency injection framework will provide that for us. So to create an instance of Person class, all we need to do is call something like:

dependecyFramework.getInstance(Person.class)

Magically, (not really), the dependency injection framework will create an instance of the Person class and provide an instance of the MessageService to the Person object.

The next natural question will be, how does the dependency injection framework knows how to initialise the MessageService? We need to tell the dependency injection framework how to create an instance of MessageService. With Guice we do that by creating a module (a class that extends AbstractModule class) as illustrated below.

package com.javacreed.examples.di.part2;

import com.google.inject.AbstractModule;

public class ProjectModule extends AbstractModule {

 @Override
 protected void configure() {
   bind(MessageService.class).to(EmailService.class);
 }
}

Here we are telling the dependency injection framework (Guice) how to create an instance of the MessageService class. We also need to add an annotation to the Person class in order to allow the dependency injection framework to inject the necessary parameters.

package com.javacreed.examples.di.part2;

import com.google.inject.Inject;

public class Person {
 private MessageService messageService;

 @Inject
 public Person(MessageService messageService){
   this.messageService = messageService;
 }

 public void greetFriend(){
   messageService.sendMessage("Hello", "Hello my friend :)");
 }
}

Note that the same concept can be applies to Spring or other dependency injection frameworks. Each dependency injection framework has its way of configuration and the above only applies to Guice. Spring and the others dependencies injection frameworks make use of different configuration methods.

With everything set, we create an instance of the Person class using the dependency injection framework.

package com.javacreed.examples.di.part2;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class Main {
 public static void main(String[] args) {
   Injector injector = Guice.createInjector(new ProjectModule());
   Person person = injector.getInstance(Person.class);
   person.greetFriend();
 }
}

We replaced a couple of lines of code with many others. What’s the buzz about this? In the next section we will see some of the benefits of dependency injection and how this can be used to simplify our coding life.

Benefits of Dependency Injection

In this section we will see some key benefits of dependency injection

  • Changing the message service

    Let’s change the delivery method from email to SMS. How would we do that?

    We only need to change the ProjectModule class to map the MessageService class to the SmsService class as highlighted in the following example.

    package com.javacreed.examples.di.part3;
    
    import com.google.inject.AbstractModule;
    
    public class ProjectModule extends AbstractModule {
    
     @Override
     protected void configure() {
       bind(MessageService.class).to(SmsService.class);
     }
    }
    

    This one change will affect all classes initialised with the dependency injection framework without having to change any of these classes. This leads us to another advantage: testing.

  • Testing and Mocking the message service

    We can create a MockMessageService class which can be using in JUnit test case as shown next.

    package com.javacreed.examples.di.part3;
    
    public class MockMessageService implements MessageService {
    
     public String subject;
     public String message;
    
     @Override
     public void sendMessage(String subject, String message) {
       this.subject = subject;
       this.message = message;
     }
    }
    

    The above mock message service simply stores the parameters into two public fields. These fields can be used to retrieve the values of the parameters and used for testing ass illustrated next.

    package com.javacreed.examples.di.part3;
    
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    
    import com.google.inject.AbstractModule;
    import com.google.inject.Guice;
    import com.google.inject.Injector;
    import com.google.inject.Singleton;
    
    public class TestPerson {
    
     private Injector injector;
    
     @Before
     public void init() {
       injector = Guice.createInjector(new AbstractModule() {
         @Override
         protected void configure() {
           bind(MessageService.class).to(MockService.class);
         }
       });
     }
    
     @Test
     public void testGreetFriend() {
       Person person = injector.getInstance(Person.class);
       person.greetFriend();
    
       MockService mockService = injector.getInstance(MockService.class);
       Assert.assertEquals("Greet", mockService.subject);
       Assert.assertEquals("Hello my friend", mockService.message);
     }
    }
    

    This may require some explanation. So here we go. In the init() method we created a dependency injection context just for this testing and provided a custom module (as an inner anonymous class). The custom module wires the MessageService with the MockMessageService instead. After the greetFriend() method is invoked, we ascertain that the correct parameters are being passed to the message service instance.

    This design setup allows us to test the Person class independent from the other classes that it depends on in an automated manner.

  • Changing the signature of the Person constructor

    As we mentioned in the list of limitations, the Person class may evolve and include more functionality. Changing the signature of the Person constructor will not affect us as long as the injector knows how to provide the required parameters.

    package com.javacreed.examples.di.part3;
    
    import com.google.inject.Inject;
    
    public class Person {
    
     private final MessageService messageService;
     private final WritingService writingService;
    
     @Inject
     private Person(final MessageService messageService, WritingService writeService) {
       this.messageService = messageService;
       this.writingService = writeService;
     }
    
     public void greetFriend() {
       messageService.sendMessage("Hello", "Hello my friend :)");
     }
     
     public void writeToFriend() {
       writingService.write("Hello my friend :)");
     }
    }
    

    The Person class will still be initialised in the same way as it is now. Thus changing the Person constructor signature will not affect the other classes that make us of it.

    Person person = injector.getInstance(Person.class);
    

    The same applies for anything that is initialised and handled through the dependency injection framework.

  • Passing the Injector as parameter

    In a project we can have one instance shared throughout the project. This can be achieved by passing the Injector as a parameter to other objects that need it. We setup the Injector at the beginning (in a main() method for example), and then have it set as a constructor parameter in all the classes that require an instance of the injector. Like that, one injector will server all classes in the project.

Conclusion

This ended up to be quite a long article. Dependency injection is quite simple to use and it has quite a “shallow” learning curve. This article did not explain how to use the actual dependency injection framework (such as Guice or Spring). Articles about these are easily found. This article described key benefits of using a dependency injection framework, even in small projects.

Albert Attard

Albert Attard is a Java passionate and technical lead at a research group. You can find him on . Over the past years Albert worked on various Java projects including traditional server/client applications, modular applications, large data handling applications and concurrent data manipulation applications to name a few. He has a BSc degree from the University of London (Homepage) and an MSc Information Security with the same university. His MSc thesis (Book) received the 2012 SearchSecurity.co.UK award (Website).

75 Responses to “Why should we use dependency injection?”


Julio
March 15, 2013 Reply

“Someone that knows how to do the tea just the way we want it. Would that be better than making the tea ourselves? If yes, then welcome to dependency injection”

That’s why people get married 😀

Quiana
July 7, 2013 Reply

Very useful article. Thank you very much!

subba
August 16, 2013 Reply

Tried lot of other sites but I did not understand what exact problems with dependency , you have given a clear examples. thanks

Vipin
September 6, 2013 Reply

Heard about Dependency Injection, but this article give a fair idea about the same. Thanks a lot.

jay
September 17, 2013 Reply

You absolutely answered all my lingering questions. This has been most helpful and really appreciated

Albert Attard Albert Attard
September 17, 2013 Reply

Welcome. I’m glad you liked it.

Serkan Algül
September 25, 2013 Reply

amazing!

Ponsuyambu
October 9, 2013 Reply

Thanks yaar !! I understood the base concepts :-)

Rahul A
October 9, 2013 Reply

Finally, I could understand the need for Dependency Injection!
Thanks a lot to you!

Asif
October 26, 2013 Reply

Went through a lot of sites to understand the dependency injection concept and guice (including the guice homepage) – but couldn’t really grasp the concept.
This article, indeed is succinct and elaborate at the same time – it helped me to understand the basic concepts clearly.

Thanks a lot for putting this up.

Albert Attard Albert Attard
October 26, 2013 Reply

Thank you for your feedback. I am glad this article helped you. Please do let me know if there are other topics which you would like us to write about.

Shailesh Karwa
December 6, 2013 Reply

Thank you very much Albert Attard. Finally, I could understand the need for Dependency Injection! I tried to understand a lot through other pages but you explained it very good.
Thanks a lot to you!

Albert Attard Albert Attard
December 6, 2013 Reply

I am glad that this article helped you understand dependency injection better.

Suraj K
January 5, 2015 Reply

You have explained very well about DI. Could You Please elaborate this Topic in .Net Language.

Albert Attard Albert Attard
January 8, 2015 Reply

Hi,

Thank you for your comment. Unfortunately I do not have any .Not experience. But the concepts should be very similar and I am confident that there are Dependency Injection Frameworks for .Not too.

Best of luck

Krishna
December 17, 2013 Reply

Very good article and it is very useful too.

Tien Cuong Kieu
January 8, 2014 Reply

Very nice article. Very clean and easy-to-follow. Thanks a lot.

Srikanth
January 15, 2014 Reply

Great one Albert… Loved your article. You really don’t how stressed am in not understanding the concept of Dependency Injection from several days reading in all other websites. This is the One which made my day. Thanks a lot :)

Albert Attard Albert Attard
January 15, 2014 Reply

Thank you. I’am glad you liked it.

sindhu
January 16, 2014 Reply

Loved the article..I have easily understood the topic..

pranav
March 2, 2014 Reply

great article…..very useful and easy to understand….u hav explained DI very simply….i haven’t read such simple explaination like this anywhere….:)….looking for ur next articles….:)

Mohammad Chehab
March 12, 2014 Reply

EXCELLENT ARTICLE!!! BETTER THAN MARTIN FOWLER HIMSELF!!

Albert Attard Albert Attard
March 12, 2014 Reply

Thank you for your comment. I am glad you liked the article.

I read most of Martin Fowler’s (Homepage) books and these are very interesting. He is a very good author.

Latha Kamath
March 21, 2014 Reply

Very well written. Thanks. The simple code examples help.

good job
March 27, 2014 Reply

You did a good job explaining dependency injection. But I am not at all convinced this provides any meaningful advantages. This requires a lot of planning and foresight.

But it seems to me that, if you have that level of foresight and planning, you can accomplish the same things in a less convoluted way.

Albert Attard Albert Attard
March 27, 2014 Reply

Thank you for your comment.

Dependency injection is not a must, and I am sure that you can find many successful projects that do not use dependency injection. With that said, if you do not use a dependency injection framework, you end up in creating one (or parts of it) yourself. Furthermore, dependencies can be passed through constructors or setters and this can be achieved without dependency injection. The benefit of dependency injection is that the framework takes care of all objects creation and configuration for you. Therefore instead of creating and configuring the objects yourself, the dependency framework does it for you.

I have used dependency injection for some time and while it is true that it is yet another thing to learn, it is also true that it is worth it. I recommend you give it a try and you will see how this can help you and how it can simplify your work. You can recommend a scenario if you like and we can discuss it here.

Abbas
April 13, 2014 Reply

My thought:
Creation of dependency injection has a tight relation to run time binding. When there is no need for run time binding (like the example you provided) the usability of DI frameworks is so limited, I think. Definition of MessageService is a good practice but can be achieved without any DI framework. In the example above, we coded more code and added more complexity to the code. So, I think if we rewrite the code with MessageService and just use simple constructor, the result would be more readable, easier to debug.

Using Guice is just like keeping a static Map and read all the objects from there. Do you think it is a great idea? So, I think we need to use Guice or any DI framework only when:

  • We need run time bindings (Plugin pattern), or
  • We have a huge configuration hierarchy and we frequently change the configuration of child components (to be honest I think in many cases it would be a sign for a bad design)
Albert Attard Albert Attard
April 13, 2014 Reply

Thank you for your input.

Your comments are fair and make sense, especially for small applications, but I believe that you are missing one thing. Who is responsible from creating and managing the life-cycle of your objects/services? While it is true, that DI needs to be configured, with your suggestion you are implementing your own DI. Furthermore, both Spring and Guice are JSR330 compliant (JSR) and thus if your code only uses code compliant to JSR330, then it can work on any framework that honours this.

Say you have a small application that connects to a database. Then you will make the data source available to all code through a singleton. Who is managing this code (the code that makes the data source a singleton)? You need to do that. Whereas if you use a DI, you can configure the data source as singleton and injected where required.

My thoughts:

  • DI is yet another technology to learn and this can turn developers away. We are already busy with a tight schedule and this makes it hard to allocate time to learn DI. This can be challenging as we are already very busy with many things and DI is not something that you install and forget about it. It needs to be mastered.
  • DI centralises objects creation and life-cycle management. If all projects use DI, then moving from one project to the next would be simpler as you know that most objects/services are managed through the DI.

    If you google about the singleton pattern, you will see several implementations and suggestions (and some of them are broken too). The chances are that the next project uses a different method to handle singletons, thus knowledge cannot be easily transferred between projects. DI reduces this problem. Furthermore, if you see a method with the annotation @PostConstruct, then you know that this method will be executed by the DI once the object is created. Same applies to the other annotations.

  • DI promotes business logic code over boilerplate code. While you may think that DI has unnecessary overheads, DI actually reduces the boilerplate code and helps you to be more efficient. Say you want to have the data source as singleton. You configure the DI so that the data source is singleton. This is a business requirement and there is no additional code. You do not have to create the code that makes your data source a singleton and worry about multiple threads and things like these. You do not need to call the post initialisation and disposal methods as the DI does this for you.

Hope that my thoughts help you understand DI better.

Abbas
April 14, 2014

Thanks for the reply.
This is a kind of discussion that I really like. I hope I do not discourage you by my critique.
First of all let’s be consistent with naming. Let’s call what Guice and Spring provide (runtime configuration) as Dynamic DI or DDI and other methods that can bind objects during compilation time as Static DI or SDI.
Lets talk about the complexity that DDI frameworks add to the code, especially the ones with annotations. I read in several references and I also believe that DDI damages the readability of the code. Theoretically, you cannot say what object is bound to what without executing the code (or manual tracing the code). It is true because it is the nature of DDI. Guice promises you that your software will be configured at run time. So, technically you can’t tell the bindings at compilation time. To me it is a big disadvantage if your problem does not need run time configuration. The other disadvantage some people refer to is exposing internal data structure with bindings. Sadly, this is what happen in real life without a well managed configuration hierarchy.
So in order to justify usage of DDI we have to compromise these disadvantages with advantages of the same weight or more.
I think the benefits that you mentioned are good ideas but in practice they don’t help that much. For example, I don’t think making a singleton would be a hassle for a software engineer that works on a big project that really needs SDI or DDI. Regarding life cycle management, I am doubtful about real implementations of that with DI, say how DI framework would know when and how destroy the objects. After all, you have to write the code for all those life cycle events particularly for each class you inject. The help from DI framework is just calling those methods. So there is not a huge boilerplate code in there. If I am wrong, we can implement a project with and without Guice and see how much boilerplate code would be saved in real examples with Guice (and how much boilerplate code is added because of that, e.g. definition of annotations)
To be honest, I worked with many codes written with Guice, I have seen the damage to readability but I can’t remember anyone used Guice for life cycle management as DI frameworks promise.

Bottom line, I would say:
– If we need run time configuration, DDI is almost the right solution, otherwise we are kind of reinventing the wheel in many cases.
– If we don’t need run time configuration we have to consider all the advantages and disadvantages of DDI before jumping to go with one DDI framework. We have to consider old SDI methods as well, e.g. factories.

Anyway, to be honest, when I read your article I felt that you are trying to bundle modular programming with DDI and you try to sell both. So when you mentioned advantages, you listed advantages of modular programming as well. Unfortunately, I saw the same thing in some other references as well. So, what happens in many cases is that a beginner unconsciously believes that he/she needs to define some components and services and then he/she MUST use a DDI framework without even thinking about something like a factory. Believe me, I saw a vast number of those over-engineering in projects that would never ever get close to a point to take benefit of the advantages you mentioned above.
So, I thought that we can start this discussion to dig into the issue and discuss the real advantages/disadvantages of DDI (not the ones that comes from any modular programming paradigm).
Thanks.

Albert Attard Albert Attard
April 23, 2014

Let say that we have a service named: PrintService, which takes a string and prints it (or does something with it), and this service is used by other classes, referred to as consumers. How will the other classes (consumers) obtain a reference to this service (PrintService)? You can pass it via constructor when creating these classes (consumers), or through setters methods. Who is creating these classes that consume this service? You are as shown next.

ConsumerA ca =new ConsumerA(MyFactory.getInstance().getPrintService());

ConsumerB cb =new ConsumerB();
cb.setPrintService(MyFactory.getInstance().getPrintService());

This is what we did before dependency injection frameworks became popular.

With dependency injection frameworks (forgive me if I did not follow your naming conversion but I did not understand them), such as Spring or Giuce, these classes (consumers) that require this service (PrintService) are created by the framework and these classes are wired by the framework too. So all you need to do is declare them as shown next.

@Inject
ConsumerA ca;

@Inject
ConsumerB cb;

If you prefer the other approach, please use that one. I always stressed out that developer should always develop with technologies and methods they feel comfortable with.

In my opinion, large projects benefit from this (dependency injection), as the developer does not need to worry about objects creation and wiring. In other words, with dependency injection, you delegate the creation and wiring of objects to the framework. Furthermore, the tests classes may require different mock services, such as MockPrintService, which can be achieved through factories as well as the MyFactory.getInstance().getPrintService() will return an instance of the mock service instead. This approach may have a scope issue and multiple tests (using different mock implementations) may interfere with each other especially if the tests are executed in parallel.

Please appreciate that I am not here trying to convince you or anyone to use dependency injection. It is clear that we have a different view and opinion about this matter and I am confident that your point of view is valid. My intention was (and still is) to share my experience and help others understand what I perceive as benefits of such frameworks.

Abbas
April 24, 2014

I see your point and your intention and I really appreciate that. I just wanted to add some complementary materials to give more information to readers to make a more wise selection perhaps.
Good luck.

Albert Attard Albert Attard
April 24, 2014

Thank you.

Umar
April 4, 2014 Reply

What a bombastic article. I was surfing Internet for a week but did not understand “What is Dependency Injection”. but after reading I have clear idea about Dependency Injection… Keep It Up. my friend.
Thanks for Sharing…

Aria
May 24, 2014 Reply

Best explanation of DI I’ve ever read!!Great job..

kiran
May 27, 2014 Reply

gr8 Article

kiran
May 27, 2014 Reply

gr8 Article, gr8 job keep writing

Ravi
May 27, 2014 Reply

Great Article and discussion. Thanks

srujan
June 21, 2014 Reply

thank you sooo much….finally got the point

Julien
September 5, 2014 Reply

Very well Written ! Thanks a lot

Naga
October 18, 2014 Reply

Great explanation in bits!

KiranRaj EL
March 6, 2015 Reply

This is a great article to understand the concepts of DI and Guice.

Great work.

Thanks

Albert Attard Albert Attard
March 6, 2015 Reply

Thank you. I am glad that you liked it.

Isakkiraj
April 30, 2015 Reply

This only one of the site, which explain about DI. Actually i am .net developer. I can’t find any article for .net. But your article is common for all (I am trying to say is that much of great article is yours). We need your sewa in .net also.. Great job…

sivakumar
July 22, 2015 Reply

if u change service class (message service)constructor parameters client class(person) wont affect.that is dependency injection advantage.
but u r saying reverse.please check once.

Albert Attard Albert Attard
July 22, 2015 Reply

I am not following you. Can you please elaborate with an example?

Tim Pizey
October 22, 2015 Reply

I enjoyed this article, it is well written.

The problem is the idea that ‘we should’ use dependency injection.
We should code to interfaces but the situations in which dependency injection is appropriate are few and far between. Most of your use cases are redundant now that we have IDEs which can refactor properly.

In general, as a Spring user, I think we can say the dependency injection craze was a failure.

Dependency Injection, using XML and introspection, removes the type safety which is the strong point of Java, for no worthwhile benefit.

Albert Attard Albert Attard
October 24, 2015 Reply

Thank you for your feedback.

I do not agree with your points and I believe that dependency injection is quite convenient. It is not a refactoring problem but a wiring one. When creating services or consumers, you do not have to worry about passing in the dependencies. The framework will do that for you.

Naveen Kocherla
October 27, 2015 Reply

Hi Albert Attard ,

I read many articles about dependency injection every article says more or less same with different approach in explanation.

You used MessageService, some one used Moviefinder, etc.

I am thinking that, unless we have different implementations for our interface, and the same interface used in many places this dependency injection is not much useful. If so I mean different implementatons, different places this is where the DI come in to picture.

For example In your case, I know that there is only one EmailService no other service and it is used at only one place. So, in this case also we can use DI but its not much useful.

For getting a simple EmailService object this much of configuration, etc…

Of course in real time we will use DI, we will not follow different approaches to get the service objects.

Please let me know whether my thinking is correct or not?

By the way its really very very good article. Like it so much.Crystal clear explanation. keep it up. Very helpful.

Albert Attard Albert Attard
November 2, 2015 Reply

Hi Naveen Kocherla,

Thank you for your feedback.

Program to interfaces and Dependency Injection are two different things. Services should be defined as interfaces and then pass to the consumers instead of the actual implementation. So far we have not mentioned dependency injection. Dependency injection wires up your objects with their dependencies which dependencies may be classes and not simply interfaces. Thus dependency injection wires your objects for you. The example used in this article was having someone doing the tea for you, without you having to worry about that.

To address your query about the single implementation. In general we test our code and we do so using mocks instead of the production service. The mock is an alternative implementation and thus you have at least two implementations. Furthermore, in order to be able to use the mock during testing, you need to provide with setter method to set this service.

Consider the following example.

public class ObjectBeingTested {

  MyService service;

  public void setService(MyService service){
    this.service=service;
  }
}

The above class needs one service, of type MyService. When testing the above class, we need to pass the service (an instance of MyService) as shown next.

MyService mock = ...;

ObjectBeingTested obt = new ObjectBeingTested();
obt.setService(mock);

In the production environment, we can have the dependency injection framework (Spring, Guice or any other), to wire this instance with the required service.

How is this useful? In a world of services, say that now we need to add a second service to our object. We simply add the new dependency and the correct annotations/configuration and all is set. You do not need to worry about this as the dependency injection will wire your new dependency without you have to worry about it. Needless to say, the new dependency needs to be available.

khaled
November 5, 2015 Reply

Great article, Thank you guy !

khad
November 23, 2015 Reply

Thanks a lot sir for posting such a well explanation. Really nice work, keep it up, please! Well done!

Ken
February 23, 2016 Reply

Thanks for the article – clarified the need or DI quite a bit. I still have a couple questions though:

#1
If I have a file with multiple creations of objects implementing the Animal Interface and all those objects were new Mouse(), it would be much easier to call DIFramework.inject(Animal) (or whatever the notation is) in all instances. That way, if I want to change all the instances to new Dog(), I just have to bind Dog to Animal instead of Mouse to Animal. However, what if the project used many different classes that implemented the interface, Animal? So an instance of new Cat(), new Duck(), new Frog()… How would I specify which class I want each of the objects to be in the configuration file?

#2
Is DI required/recommended for individual projects (only me working on it), or should I just go with the traditional use of interfaces?

Albert Attard Albert Attard
February 26, 2016 Reply

Hi,

Sorry for my late reply. Please find my answers below.

  1. Animal is very generic and thus any implementation will do. If you want something specific, you can dictate the type by using the binding annotations. This article provides some useful examples which can help you with your question.
  2. You can use dependency injection anywhere you like. A small project may not need it but I still recommend using DI as this promotes better design.

Should you have further queries, please do not hesitate to contact me.

balu
April 21, 2016 Reply

what is the limitation of dependency injection

Albert Attard Albert Attard
April 22, 2016 Reply

This is quite a generic question and like all technologies it has its advantages and disadvantages. Dependency injection is yet another technology to learn and this can prove challenging for someone new to the field.

Excellent article! We will be linking to this particularly great
post on our site. Keep up the good writing.

Albert Attard Albert Attard
May 9, 2016 Reply

I am glad you liked it.

Charles
September 25, 2016 Reply

This was the clearest article on DI, thanks! still i wasnt convinced about the benefits, because replacing sendEmail with sendSMS seems too easy to look for more complex solutions. Also sendMock can be written and called as we wish…You have much patience, answering every question so gracefully, very impressive..

Albert Attard Albert Attard
December 31, 2016 Reply

I am glad you liked it. As you said the example is naïve, as it is not always easy to use complex examples and still delivers a simple message. DI can simplify the developers’ task by taking care of the wiring of components and somewhat promotes the use of interfaces.

Ankush Mishra
January 3, 2017 Reply

Thanks a lot :)

Bang Pham Huu
January 22, 2017 Reply

I think you missed type with MockMessageService and MockService, e.g: bind(MessageService.class).to(MockService.class);

Randy Lutcavich
February 5, 2017 Reply

This is a great explanation.

Fyi, there’s a couple small typos:
Actual: Some of the example shown…
Expected: Some of the examples shown…

Actual: …does not provide detailed description…
Expected: …does not provide a detailed description…

Actual: Let say we want to make some tea.
Expected: Let’s say we want to make some tea.

Actual: Let say we have a class,
Expected: Let’s say we have a class,

Actual: Let say we have a new and better version…
Expected: Let’s say we have a new and better version…

Actual: Let say we parameterise…
Expected: Let’s say we parameterise…

Actual: …to make the Email class Singleton…
Expected: …to make the Email class a Singleton…

Actual: The projects ends up with two…
Expected: The project ends up with two…

Actual: …how would we automate such test?
Expected: …how would we automate such a test?

Actual: …to automate out tests?
Expected: …to automate our tests?

Actual: …another class that allow this object…
Expected: …another class that allows this object…

Actual: …make the Person class using this interface instead.
Expected: …make the Person class use this interface instead.

Actual: …can help us initialising objects…
Expected: …can help us with initialising objects….

Actual: …how does the dependency injection framework knows how…
Expected: …how does the dependency injection framework know how…

Actual: (a class that extends AbstractModule class)
Expected: (a class that extends the AbstractModule class)

Actual: …same concept can be applies to…
Expected: …same concept can be applied to…

Actual: Spring and the others dependencies injection frameworks…
Expected: Spring and the other dependency injection frameworks…

Actual: …which can be using in JUnit…
Expected: …which can be used in JUnit…

Actual: …for testing ass illustrated next.
Expected: …for testing as illustrated next.

Actual: …classes that make us of it.
Expected: …classes that make use of it.

Actual: Passing the Injector as parameter
Expected: Passing the Injector as a parameter

Actual: …one injector will server all classes in the project.
Expected: …one injector will serve all classes in the project.

Albert Attard Albert Attard
February 7, 2017 Reply

Thank you very much for your valuable contribution to this article. I really appreciate your input and have applied all corrections. Please feel free to read and send me feedback about any other articles in this website. I can send them to you in Word format if you prefer and you can apply the corrections directly.

Thanks again for taking the time and send me the feedback.

hilal
February 23, 2017 Reply

the link http://java-creed-examples.googlecode.com/svn/dependency-injection/WhyUseDependencyInjection/
point to path that doesn’t laod (404 error)
can you update the link please?

thanks

Albert Attard Albert Attard
March 12, 2017 Reply

The code referred into my dependency injection article was moved to https://github.com/javacreed/why-should-we-use-dependency-injection after Google closed their code repository some years ago, but never updated the link on the page. Thank you for letting me know.

Abdul Mueed
April 21, 2017 Reply

This is very good article actually the only one where I could understand why even bother to use it.
I just have one questions. What if I want to use multiple ways of sending messages lets say person object provides method to send text message, tweet, and email. in this kind of case, do we still use dependency injection? if yes what is best case i mean best way to do it.

Albert Attard Albert Attard
August 14, 2017 Reply

Hi Abdul Mueed,

You can create a chained message sender which will take a message and then it will send the message to all other senders. This can use different threads so that one message sender does not block the other. In real applications a message queue is used where a message will be send and all those that can process it (one or many message senders) will process it.

Sorry for the delay and how that my reply answers your question.

Boris
October 1, 2017 Reply

Hello Albert,
thank you for your article. This is great explanation of DI framework. According to your example with MessageService, could you explain me one thing? You have annotated constructor with @Inject. Can we annotate only field messageService instead of constructor? Then we could remove this specific constructor.

Best Regards

Albert Attard Albert Attard
October 2, 2017 Reply

Hi Boris,

Services can be injected by the framework, such as Google Guice or Spring, through the constructors as shown in this article, setting the fields directly or through setter methods. I prefer the constructor version in general for several reasons. The object cannot exists without the services it depends on.

Regards

PG
December 22, 2017 Reply

One of the best articles I have read on DI. I thoroughly enjoyed the back and forth between Abbas and Albert too. Discussions like this add a ton of value to the tech community

rz
February 15, 2018 Reply

Definitely the best materials out there for explanation of DI and why it is useful. I have read tons and I can only follow this post here.

Aetherus
February 28, 2018 Reply

In my opinion, the objects that have very long lives (e.g. controllers and service objects) are often the objects that have no internal states, and are often unreplaceable. So why not instead just define such classes that contain only static methods? This eliminates the necessity of DI, and shorter class definition (because we don’t need fields any more), plus better performance (because calling static methods doesn’t involve runtime method lookup, and static methods have better chances to get inlined by JVM), and shorter startup time. The only drawback of this approach I can think of is that there’s no automatic database transaction management, but that’s not a big deal because we can easily implement transaction management in functional programming style, and that again eliminates the need of AOP which is a very very black magic in Java.

Albert Attard Albert Attard
June 24, 2018 Reply

Thanks for your input.

Static methods are easy to use and very convenient as you explained. The only issue with the static methods is that you are hard-coding the consumer of the static method with the implementation, which may complicate tests. If the consumer is calling the static method from within, then you cannot replace it with mocks during testing.

sudheer
May 9, 2018 Reply

nicely explained. Thank you very much!

priya
June 4, 2018 Reply

Interfaces are mainly used to provide polymorphic behavior. Interfaces function to break up the complex designs and clear the dependencies between objects.

Leave a Comment


Time limit is exhausted. Please reload the CAPTCHA.