DI and IoC: Creating And Working With A Cloud Of Objects

A few months ago, I posted some thoughts and questions on the proper use of Inversion of Control (IoC) containers and the Dependency Inversion (DI) principle. Since then, I’ve had the opportunity to do some additional study and teaching of DI, and I’ve had that light bulb moment for the proper use of an IoC container. I haven’t talked about it or tried to present the info to my team(s) yet, because I had not verified my thoughts were on the right track – until recently. I got to spend a few hours at the Dovetail office with Chad, Jeremy, Josh, etc, and had the pleasure of being able to pick their brains on some of the questions and thoughts that I’ve had around DI and IoC. In the end, Chad confirmed some of my current thoughts and helped me put into a metaphor that I find to be very useful in understanding what Dependency Inversion really is – a cloud objects that can be strung together into the necessary hierarchy, at runtime.

Consider a set of classes that need to be instantiated into the correct hierarchy so that we can get the functionality needed. It’s really easy to have the highest level class – the one that we really want to call method on – instantiate the class for next level down, and have that class instantiate it’s next level down, and so-on, like this:

image

This creates the necessary hierarchy, but breaks the core object oriented principle of loose coupling. We would not be able to use ThisClass without bringing ThatClass along with it, and we would not be able to use ThatClass without bringing AnotherClass along with it.

By introducing a better abstraction for each class and putting Dependency Inversion into play, we can break the spaghetti mess apart and introduce the ability to use any of these individual classes without requiring the specific implementation of the dependent class.

For starters, let’s introduce an interface for ThisClass to depend on and an interface for ThatClass to depend on.

Adding Dependent Interfaces

Now that we have an interface that both of these classes can depend on, instead of the explicit implementation of the child object, we need to have the expected child object implement the interface in question. For example, we expect ThatClass to be used by ThisClass, so we will want ThatClass to implement the IDoSomething interface. By the same notion, we want AnotherClass to implement the IWhatever interface. This will allow us to provide AnotherClass as the dependency implementation for ThatClass. Our object model now looks like this:

Implementing Dependency Interfaces

What we have now is not just a set of classes that all depend on each other, but a “cloud” of objects with dependencies and interface implementations that will let us build the hierarchy we need, when we need it.

The Cloud Of Objects

The real beauty of this is that we no longer have to care about the implementation specifics of IDoSomething from ThisClass. ThisClass can focus entirely on doing it’s duty and calling into IDoSomething when it needs to. And, by passing in the dependency as an abstraction, we’re able to replace the dependency implementation at any time – runtime, unit test time, etc. This also makes our system much easier to learn and understand, and most importantly – easier to change.

Now that we have our cloud of implementations and abstractions in place, we will need to reconstruct the hierarchy that we want so we can call into ThisClass and have it perform it’s operations. Here’s where Dependency Inversion meets up with Inversion of Control.

  • To create ThisClass, we need an implementation of IDoSomething
  • ThatClass implements IDoSomething, so we’ll instantiate it before ThisClass
  • ThatClass needs an instance of IWhatever
  • AnotherClass implements IWhatever, so we’ll instantiate it before ThatClass
  • Once we have AnotherClass instantiated, we can pass it into ThatClass’s constructor
  • Once we have ThatClass instantiated, we can pass it into ThisClass’s constructor

We end up with a hierarchy of objects that is instantiated in reverse order, like this:

Reconstructing The Hierarchy Of Depdencies

We have now successfully inverted our system’s construction – each implementation detail is created and passed into the the object that depends on it, re-creating our hierarchy from the bottom up. In the end, we have an instance of ThisClass that we can call into, with the same basic hierarchy of classes that we started with. The real difference is that now we can change this hierarchy at any time without worrying about breaking the functionality of the system.

Once we have our Dependency Inversion and Inversion of Control in place, we can start utilizing the existing IoC frameworks to automatically create our hierarchy of objects based on the advertised dependencies (an advertised dependency is a dependency that is specified as a constructor parameter of a class). Tools like StructureMap, Spring.net, Windsor, Ninject, and others, all provide automagic ways of creating each dependency of the object that is requested, all the way up/down the hierarchy. Utilizing one of these IoC containers can greatly simplify our code base and eliminate the many object instantiations that would start to liter our code. As I said in my previous post, I know all about what not to do with IoC containers. Good IoC usage, though, is another subject for another post.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Analysis and Design, Design Patterns, Principles and Patterns, Refactoring, Unit Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.timvw.be Tim Van Wassenhove

    I’ve got the feeling that after this you’ll want to automate the manual composition of dependencies and end up with something like http://www.qi4j.org/ for .Net

  • http://colinjack.blogspot.com Colin Jack

    @Tim
    I’ve been monitoring (from a vast difference) http://www.qi4j.org/ for a while, seems very interesting but a massive change in how we all work. Will it be the next SOA/DDD type shift though?

  • shovavnik

    When you say “We have now successfully inverted our system’s construction”, don’t you actually mean “We have now successfully constructed our inverted dependencies in the correct order automatically”?

    That is, the construction hasn’t been inverted; it’s in the same order it would have been if you had done the construction manually.

  • http://www.lostechies.com/blogs/derickbailey derick.bailey

    @shovavnik

    no – the order in which objects are constructed is now inverted. In the original diagram, ThisClass was constructed first, it then constructed ThatClass, which then constructed AnotherClass.

    By the end, though, we are constructing the objects in the opposite order; inverted from the perspective of what class we actually want to call. We have to build AnotherClass first, then pass it into the construction of ThatClass, then pass ThatClass into the constructor of ThisClass.

  • Kyle

    It’s not important at all, but I’ve always heard the DI with respect to IoC mean “dependency injection”. When referring to the dependency inversion principle, most authors refer to it as the DIP.

    I view dependency injection as slightly differently because it is the method by which we go about achieving the dependency inversion principle.

  • http://www.lostechies.com/blogs/derickbailey derick.bailey

    @Kyle,

    Yeah, I should probably standardize on DIP for those reasons. I’ve confused more than one person by getting those two mixed up like that.