Dependency Injection

Inversion of control – IoC – is a concept, and an associated set of programming techniques. In the traditional interaction model of an application, the programmer specifies a series of events to happen by making a series of function calls. eg. a programme which takes a name from the command line and displays it back would follow this model, all the user can do is enter a string and then hit return ie. the flow will always be the same. In an application with GUI however we might have an input field and a submit button and although very simple the flow control will not necessarily be as straightforward:

eg.

  • the user could enter several different strings and change them before submitting;
  • they may repeatedly hit submit;
  • they might close the window before doing anything;

In the second case, the programmer will set up some responses to particular events of interest ie. the submit button being pressed; the window being closed; and then explicitly gives up the control, usually by putting the code in an
infinite loop in which the application will wait for and react to events. The programme will usually be programmed to exit the loop when an event happens. This example illustrates one important aspect of inversion of control: because
the programmer no longer has direct control over the order of execution of individual functions, some things must change.

The example, despite its simplicity, hints at some very significant implications of inversion of control. In the traditional interaction style, it’s immediately obvious what will happen when the programme is run. In return, such a programme is inflexible: if the programmer wanted to allow the user to correct the name before it’s submitted, or to display the greeting twice on the command line, each such scenario would need to be coded for and supported separately. On the other hand, in the second event-driven example, infinitely many possible scenarios can be realised. The price paid for that additional flexibility is greatly increased complexity and the fact that the programme is no longer deterministic: it’s no longer possible to tell what functions will be called just by looking at the code; one needs to consider the code and the environment to be able to determine the order of events. The code is also much harder to write and reason about, and computations that are naturally sequential (A needs to happen before B, such as User name must be provided before the login can be successful) can be much harder to write and understand.

Consider the simple example below:

public interface MovieFinder {  // define our interface and the find method we wish all implementation classes
to use

List findAll();

}class MovieLister {

private MovieFinder finder;          // instance
variable to reference our concrete implementation class

public MovieLister()
{                                                             // constructor

finder = new CommaDelimitedMovieFinder(”movies1.txt”);    //  we need an actual concrete class of MovieFinder and

}                                                                                         //
an implementation of findAll() to actually do the work

//  of returning our Lsit of movies

public Movie[] moviesDirectedBy(String arg) {

List allMovies = finder.findAll();

}

}

The crux of the matter is the finder object, or particularly how we connect the lister object with a particular finder object. What we really want is the moviesDirectedBy method to be completely independent of how all the movies are being stored. So all the moviesDirectedBy method does is refer to a finder, and all that finder does is know how to respond to the findAll method.

We put the code for the concrete MovieFinder class in the constructor. The name of the implementation class comes from the fact that we are getting the list from a comma delimited text file. What happens if someone else wants to use my code but their movies are not stored in a comma delimted file: a SQL database, an XML file, a web service, or just another format of text file? In this case we need a different class to grab that data. Now because we’ve defined a MovieFinder interface, this won’t alter my moviesDirectedBy method. But we still need to have some way to get an instance of the right finder implementation into place.

The MovieLister class is dependent on both the MovieFinder interface and upon the implementation. We would prefer it if it were only dependent on the interface, but then how do we make an instance to work with? We come to the concept of a plugin.

The implementation class for the finder isn’t linked into the program at compile time since we dont know what that finder is supposed to do ie. what sort of data store it needs to access. Instead we want the lister to work with any implementation, and for that implementation to be plugged in at some later point automatically. The problem is how can I make that link so that the lister class is ignorant of the implementation class, but can still talk to an instance to do its work?

A real system might have dozens of such services and components. In each case we can abstract our use of these components by talking to them through an interface (and using an adapter if the component isn’t designed with an interface in mind). But if we wish to deploy this system in different ways, we need to use plugins to handle the interaction with these services so we can use different implementations in different deployments. So the core problem is how do we assemble these plugins into an application? This is one of the main problems that the new breed of lightweight containers suach as Spring face, and universally they all do it using the concept of Inversion of Control.

For Spring the inversion is about how it looks up a plugin implementation. In the simple example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that containers such as Spring use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister. For such a process, the term Inversion of Control is too generic – this is where the concept of the Dependency Injection pattern began.

Leave a Reply

Your email address will not be published. Required fields are marked *