When I started learning how dependency injection works it was extremely hard for me to understand. Once I got what it does I still didn't quite get what the benefits of this technique were. I just thought it was some overly complex design pattern that is just making life difficult for the sake of it. After all, what is so bad about using new anyway?
Well, in this blog post I want to share what I have learned about dependency injection since leaving university and a becoming full-time programmer last September. I hope I can help a newbie to understand a little more about this design approach. Don't be frustrated, however, if you don't get it straight away: It took me the best part of my first month to really dive into dependency injection even though I had read lots of articles and blog posts about the topic.
Dependency injection vs. Inversion of control
Some authors strangely claim that DI is the same thing as IoC. I however think that DI is a type of IoC, namely to tell the to be injected object what its dependencies are. Inversion of control, to me, means something more general: That there is a predefined workflow (the control part) that the developer hooks her own components into. This principle applies to virtually all libraries and frameworks. For example, your favourite web development framework allows you to write a request handler for a URL, but most likely you can't change the nature of the request itself. You will always receive a HttpRequest as the input of your request handling code. Dependency injection however is a specialisation of this principle.
Modules and dependencies
When you start to build big systems you naturally tend to modularise. Lets take online shopping as an example. You have one module of your code handling the user input for an order and validating form fields; lets call this module the OrderHandler. Then you have another module, which opens a connection to your payment provider and checks that the credit card data the user just gave are actually kosher and the payment can go ahead. We call this module the CreditCardPaymentService.
So, when the OrderHandler has validated all the form fields it passes the data over to the CreditCardPaymentService. But before it can do that it needs to have or create an instance of the CreditCardPaymentService. In (pseudo-) code this would probably look something like this:
So far, so good. But what happens when you have quite a few parts of your code taking orders and querying the PaymentService? They all call new CreditCardPaymentService.
Now, your boss has decided your going to switch from your old credit card provider to Paypal. You write a new PaymentProvider that sends a request to their server and authorises the payment. When you actually want to switch over, you will have to replace all instances of CreditCardPaymentProvider with PaypalPaymentProvider. Once you do these kinds of thing a lot, you'll end up thinking that there's got to be a better way to do this.
DI to the rescue
What if all the different modules of your shopping website, instead of creating new instances of PaymentProviders, would instead be given (or injected) those modules?
Maybe we could rewrite the above code like this:
Obviously now it is easy to exchange on payment provider with another one. The downside of this that you have to pre-configure the OrderHandler with some type of PaymentProvider. Most DI frameworks do this using Factories and assign each configured, ready-to-use object a string. A factory is supplied with some configuration file that defines those objects and their dependencies.
Those config files could look like this:
We now have a central piece of code that handles each module's dependencies. It basically instantiates the OrderHandler, sets the right payment service and then gives this object to whoever wants to use it. If we wanted to fetch on of the order handlers we would do it like this.
What you have done now is to externalise the configuration process of the Handler from inside it to the factory with calls the set_payment_provider method before it returns it to whoever is requesting the object.
As an added benefit we can now easily unit-test the OrderHandler by creating and injecting a fake PaymentService that always returns a positive response.
Implementations
This principle is currently used in a lot of enterprise Java applications. The most popular framework that uses this pattern is Spring. Spring uses XML files for configuration and much of what I described above stems directly from Spring, which actually many more things and DI is just one, albeit central, aspect of the framework.
Another piece of code I also want to have a look at is Google's Guice which superficially looks less all-singing, all-dancing, but still very interesting.