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: }
   7: class ClassB {
   8:    public ClassB(ILogger logger) {
   9:       // ...
  10:    }
  11: }

to this:

   1: class ClassA {
   2:    public ClassA(ClassB objectB) {
   3:       // ...
   4:    }
   5: }
   7: class ClassB {
   8:    public ILogger Logger {get; private set;}
  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:    }
   6:    // ...
   8:    public void Draw() {
   9:       // draw to the canvas
  10:    }
  11: }

might be better implemented as:

   1: public class Shape {
   3:    // ...   
   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:    { }
   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.


  1. AnonymousMay 29, 2011

    Great post, thanks for this information.


Post a Comment

Popular posts from this blog

Using xUnit.Net with .Net 4.0

I’ve been using xUnit.Net for a while now. It’s just a tiny bit cleaner and slightly less abrasive than other .Net unit testing frameworks. Leaving out unnecessary stuff like [TestFixture] and shortening Assert.AreEqual to the equally clear but shorter Assert.Equal don’t seem like big improvements but when you type them several times a day tiny improvements start to add up. I also like the use of the [Fact] attribute instead of [Test]. It shifts the focus from testing to defining behavior. So how do we get all this goodness working with the Visual Studio 2010 beta?

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 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

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.