Dependancy Injection in Layman's Terms
Posted by davidnewcomb on 27 Jan 2009 in Techie
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.
http://discuss.joelonsoftware.com/default.asp?joel.3.219431.12
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:
person_id | person_name | start_height | end_height |
# 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 end-if end-for 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 cmAfter 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:
class WhoIsTheTallest
{
OurDataSource ods;
void setOurDataSource(OurDataSource ods)
{
this.ods = ods;
}
int findTallest()
{
Person person;
int height;
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;
}
}
return tallestPersonIndex;
}
main ()
{
int tallestPersonIndex = findTallest();
Person person = ods.getPerson(tallestPersonIndex);
System.out.println(person.getName() + " has grown " + maxHeight + " cm");
}
}
In the example above OurDataSource
is an interface which implements 2 methods:
interface OurDataSource
{
int getNumberOfPeople();
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 OurDataSource
. 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 MockOurDataSource
which implements our new interface.
class MockOurDataSource implements OurDataSource
{
ArrayList<Person> people ;
MockOurDataSource ()
{
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));
}
int getNumberOfPeople()
{
return people.size();
}
Person getPerson(int index)
{
return people.get(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 ;
setup()
{
ApplicationContext ac = new
ClassPathXmlApplicationContext("config.xml");
testClass = ac.getBean("whoIsTheTallest");
}
testFindTallest()
{
int tallestId = testClass.findTallest();
assertEquals(tallestId, 3);
}
}
where config.xml
contains a description of how the class is constructed.
<bean id="whoIsTheTallest" class="WhoIsTheTallest">
<property name="ourDataSource">
<bean class="MockOurDataSource"/>
</property>
</bean>
As you can see from this example, once we have got our program working we can write a real implementation of OurDataSource
that talks to an actual database using JDBC. After learning hibernate you may want to replace the JdbcOurDataSource
with HibernateOurDataSource
. 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?1 comment
Comment from: ayan [Visitor]

Make things simple. I like that very much
Form is loading...