Skip to main content

More about dependency injection

In a previous post I talked about problems caused by singletons and how to solve them using dependency injection. I mainly talked about constructor injection. In a reaction to that post Roy Tang voiced his concerns about scaling contructor injection. In real life applications you often have a lot of dependencies, passing them through constructors can become a problem in real life solutions where you’ve got objects with lots of dependencies. Usually when manual IoC does not scale anymore I use an IoC container. But this might not always be an option. In this post I want to talk about a few ways to get around this problem.

Are you solving the right problem?

Often problems like these are indicators of other problems. The first thing to look for when you’ve got classes that have too many dependencies is the single responsibility principle. Classes often have too many dependencies because they do too much. You might want to split up that class in a few more granular classes.

One solution to avoid is reusing dependencies between classes. For example it might be tempting to rewrite this;

   1: class ClassA {
   2:    public ClassA(ILogger logger, ClassB objectB) {
   3:       // ...
   4:    }
   5: }
   6:  
   7: class ClassB {
   8:    public ClassB(ILogger logger) {
   9:       // ...
  10:    }
  11: }

to this:



   1: class ClassA {
   2:    public ClassA(ClassB objectB) {
   3:       // ...
   4:    }
   5: }
   6:  
   7: class ClassB {
   8:    public ILogger Logger {get; private set;}
   9:  
  10:    public ClassB(ILogger logger) {
  11:       Logger = logger;
  12:    }
  13: }

Eliminating ClassA’s dependency on the logger, it can just reuse ClassB’s logger, right? Well no, this breaks the single responsibility principle. The logger reference has become part of the public interface of ClassB effectively giving ClassB an extra responsibility as a LoggerProvider.


Alternatives to constructor injection.


Constructor injection is not always the right way to do things, so you might want to inject your dependencies somewhere else. Property or method injection might be good alternatives.


Property injection exposes dependencies as properties. Property injection is a bit more flexible than constructor injection but also a bit more dangerous. It allows you to set dependencies one at a time, this can be good when you’re testing something that doesn’t need the full set of dependencies reducing the size of your tests. But it can also cause objects to be only partially initialized causing problems. Property injection is very powerful but it gives you a lot of rope to hang yourself with too, be careful using it outside of an IoC container.


If a class only uses a dependency in one method you might want to pass that dependency as a parameter to that method instead of having it passed into the constructor, this is called method injection. For example the following class:



   1: public class Shape {
   2:    public Shape(Canvas canvas) {
   3:       // ...
   4:    }
   5:  
   6:    // ...
   7:  
   8:    public void Draw() {
   9:       // draw to the canvas
  10:    }
  11: }

might be better implemented as:



   1: public class Shape {
   2:    
   3:    // ...   
   4:  
   5:    public void Draw(Canvas canvas) {
   6:       // draw to the canvas
   7:    }
   8: }

Using Defaults


In addition to using different forms of dependency injection when needed you can reduce the amount of code by providing default dependencies. I wouldn’t do this in large projects because adds some coupling but it can be a good way to reduce the amount of “wiring” code and still maintain some testability.


For the ClassA class from the first example would look like this:



   1: class ClassA {
   2:    public ClassA() 
   3:       : this(new LoggerImplementation(), new ClassB())
   4:    { }
   5:  
   6:    public ClassA(ILogger logger, ClassB objectB)
   7: }

Providing you with a two options. You can then use the default constructor in your code and the DI constructor in your tests.


For large applications using an IoC container still gives you the most flexibility with the least trouble. I hope I’ve given a good overview of the options you’ve got for maintaining dependencies when you don’t have access to one of those.

Comments

  1. AnonymousMay 29, 2011

    Great post, thanks for this information.

    ReplyDelete

Post a Comment

Popular posts from this blog

Running a Git repository on Ubuntu using Gitosis

20I’ve been using Git for a couple of small projects that I’ve been hosting on github.com but version control for my bigger ‘secret’ projects still runs on a windows machine with visual svn server.Now that I’m starting to use Mono for a couple of projects so I’m playing with linux more. Last week I decided to try to try out gitosis on an ubuntu server. I found out it’s pretty easy to use when you know your way around git but for a noob like me some things weren’t immediately clear. Eventually I solved most problems I ran into, so I decided to write up the steps I took to install gitosis on ubuntu 10.04

Square One available on the Android market

This is just a short post to let you know that a first version of the Android app I’ve been working on for the last couple of weeks is available on the Android market. The app is called Square One and it’s a simple bassline synthesizer. It’s free so try it out and let me know what you think of it, but be prepared it’s still an early version. I hope to add more features in the next few months and maybe build something that can be used to create real music.The lower part of the screen contains the sequencer controls that can be used to program your own bass lines. On the left is a four by four grid of buttons where you can select a step in the sequence. On the right you can select the note to be played on that step. When you’re done you can press Start and the sequence starts playing. The knobs on the top can be used to control a couple of parameters from the synthesizer engine that creates the sound. You can control the cutoff frequency and resonance of the low-pass filter, attack and …

Android development resource links

I've been playing with the Android SDK and I have a growing list of bookmarks to Android dev resources for my own use. I thought the best place to keep them would be here on my blog. That way other people can benefit too. I'll keep updating this list so feel free to add suggestions in the comments.