Written by Roy van Rijn (royvanrijn.com) on
Jan 18, 2010 17:43:08
Learn to use Dependency Injection
Recently I placed a comment on this interesting blog from Uncle Bob Martin (Robert C. Martin). It contains a brief description on how I teach people how to use the Spring Framework.
Now, by popular demand (one person requested it over Twitter), I’ll guide you through the method and examples I use in this blogpost. It explains why people should use frameworks like Spring and/or Google Guice, and how.
Ordering Milk
Lets take a look at the application we have. We have a service:
And we have a DAO (data access object) which will take care of persisting our order:
The implementation of this DAO isn’t really interesting, lets just pretent it goes to the database:
And finally we have our service implementation:
Lets pretent that we are good obeying programmers, although we didn’t write our unit test up front, we are going to do it right away.
So… we want to test the service, how are we going to do this? Well, lets just create the service, call it, and then check if it does what we want it to do!
We run into a problem rather quickly. Now this code makes a connection to the database and it might or might not save our order. But how do we check this? We could go to the database and check…
NO! Never go to the database in a unit test. We only want to test a single unit of work, and the database ain’t one of them.
We need to refactor our code…!
The Factory
One possible solution to this problem is using a factory method. A factory creates objects so you don’t have to. Its best shown using an example:
So, lets dissect this.
The method get(class, object) will return an implementation for a given Class. It uses a Map to get the mapping. The map is created during the static initialization (yuk!) and contains the default mapping, but we can also provide our own mapping using replaceMapping(class, object).
Now how do we use it? Lets see our new MilkRequestServiceImpl:
As you can see we no longer need the constructor, we get the required DAO from the factory when we need it.
Now we can test it using the replaceMapping method:
As the comment says, you are probably much better of here using a mocking framework like EasyMock or Mockito. But the point is, we can test our class now without going to the database! We got our control back.
Dependency Injection
Instead of writing a factory, there is a better way to do this. It is the Hollywood principle “Don’t call us, we’ll call you”.
All the dependencies of the objects are injected into them instead of created (initial example) or retrieved (factory example). So our service will look like this:
Now lets take a look at our test-code, it now looks like this:
We now have full control over the wiring. First we create our own little testMilkDao (use a mock here!) and we place it into our service. That’s all. Instead of the hidden creation in the service itself or in the factory we are in full control.
But if you want to use this application you’ll need “something else” to create all the objects and do the actual wiring. Lets create our own Spring or Google Guice..!!
Using Spring
The wiring we do in the constructor is what Spring and Google Guice would do for us. In the case of Spring you’ll write something like this:
Now you’ll still need to retrieve these “beans” from Spring, this can be done using our old-friend the Factory!
It’ll look something like this:
This instructs Spring to load the XML file and create all the objects. Then we retrieve the milkRequestService and it is fully wired and ready to use!
Using Guice
Google Guice works exacly the same, only instead of using XML to define the mapping it only uses Java code and annotations.
First we tell Guice which implementations are the default implementations, for example:
We also do this to the MilkRequestService. Next we tell Guice where to inject these implementations, in this case using ‘Constructor Injection’:
Now if we want to use it, we retrieve it from Guice like so:
Thats about it, you’ve seen:
Why you should use these patterns
How you would program them yourself (ugly monkey-code-style)