Having spent the last (almost) year learning about J2EE Frameworks (specifically The Spring Framework
) I found this article very funny. It aptly describes the trials and tribulations of creating applications using framework tools, in a way that any one can understand. The article uses the analogy of building a spice rack to help describe the problems that you’ll face.
The comments are, in the most part, funny too. I think, however, that the article author and the commenters missed the point of why Spring
’s Dependancy Injection
is so useful. To be fair the article was written in 2005, so maybe they have learnt a bit more since then.
The Dependancy Injection design pattern is defined in lots of ways; most of them using more big words which have books of descriptions behind them. I would like to describe what makes Dependancy Injection useful in layman’s terms. A small knowledge of Java is required by the layman!
Let’s say you want to write an application to see which person has grown the most over the last year. You have a database full of everyone’s names, their height at the start of the year and the height at the end of the year. So your database table looks like:
and your database has 60,000,000 record’s (one record for each person in the country).
Ok, simple problem - but it requires database access, calculations and output of results. The complexity of our problem means that the program will take 2 days to run so we want to make sure that when it runs it comes out with the correct answer first time, with no bugs.
In pseudo code it is easy:
# make it smaller than the smallest diference
remember biggest_difference = -1
remember person = -1
for each person in database
height = end_height - start_height
# make it smaller than the smallest diference
if (height > biggest_difference)
remember biggest_difference = height
remember person = person_id
output person " has grown the most by " biggest_difference " cm"
After 2 days of running it spits out.
Little Jimmy has grown the most by 10 cm
After the program has run you realise that we have just wasted the last 2 days because the answer is wrong. You forgot to take into account the fact that Little Jimmy shares his growth with 100,000 other people, so we have to rewrite our program and run it again.
There must be a better way… This is where dependency injection can help us. The idea is that you split your code up into pieces. One piece gets the data for the sums and another piece does the sums and works out the answer. The bit that gets the data sits behind an interface. In our example we want to test the bit that does the sums. So we create that first to help us decide the kinds of questions we need to ask (i.e. what our interface should look like). So in Java:
void setOurDataSource(OurDataSource ods)
this.ods = ods;
int maxHeight = -1;
int tallestPersonIndex = -1;
int numberOfPeople = ods.getNumberOfPeople();
for (int index = 0 ; index < numberOfPeople ; ++index)
person = ods.getPerson(index);
height = person.getEndHeight() - person.getStartHeight();
if (height > maxHeight)
tallestPersonIndex = index;
maxHeight = height;
int tallestPersonIndex = findTallest();
Person person = ods.getPerson(tallestPersonIndex);
System.out.println(person.getName() + " has grown " + maxHeight + " cm");
In the example above
is an interface which implements 2 methods:
Person getPerson(int index);
Now that we have our interface we can write a couple of implementations. First, we will write a fake version of
. A fake object is generally referred to as a Mock
, and is usually prefixed with the word Mock
. Let’s make a really simple class called
which implements our new interface.
class MockOurDataSource implements OurDataSource
ArrayList<Person> people ;
people = new ArrayList<Person> ();
people.add(new Person(1, "Tom", 110, 190));
people.add(new Person(2, "Dick", 120, 180));
people.add(new Person(3, "Harry", 100, 200));
Person getPerson(int index)
The next class to write is a testing class, which will use our mock class as a data source. The mock class has a small amount of simple data, which means that we can work out what the answer should be by hand and use it to make sure our program is working.
class TestWhoIsTheTallest extends TestCase
WhoIsTheTallest testClass ;
ApplicationContext ac = new
testClass = ac.getBean("whoIsTheTallest");
int tallestId = testClass.findTallest();
contains a description of how the class is constructed.
<bean id="whoIsTheTallest" class="WhoIsTheTallest">
As you can see from this example, once we have got our program working we can write a real implementation of
that talks to an actual database using JDBC. After learning hibernate you may want to replace the
. Switching the implementation from one to another is a simple matter of changing the configuration file. The class source does not have to change and the class file does not have to be recompiled.
The Dependency Injection mechanism allows the separation of application and configuration. With the same compiled code you can run the application in test mode and in a live environment. Isn’t that cool?