ghytred.com


NewsLook for Outlook

Patterns and OO
IOC
The Web Site you seek
Cannot be located, so
Waste your time here

Contents

Inversion of Control

This is about reducing coupling between classes/components: the less a class depends on the more re-usable it is and the more robust in the face of changes to a system. This is Dependency Management.
The idea has been around for a while - see Robert Martins Dependency Inversion Principle and also the Hollywood Principle ("Don't call us, we'll call you", see google). This is the latest extension of the idea.

As I understand it the problem this addresses is not that a class, Foo, depends on (uses) a class, Bar. This is just the way it is and nothing can nor, assuming a sensible design, should be done about it. However, if Foo has to know how to create the Bar it needs coupling is increased: Foo may have to know about a Factory class or that Bar's should or can only be created by a Spackle class or whatever. This increases Foo's coupling with other entities in the system.

The idea is that Foo should not go out and get a Bar, but that it should be given one when it needs one. There are three types of Inversion of Control (IoC) defined:

IoC-1 aka Contextualised Dependency Lookup

In this scheme, Foo implements an IInitialise interface which is called on all classes which use IoC-1. This interface has a single method, void Initialise(), which uses a DependencyManager class to get the things it depends on:
	public interface IInitialise {
		void Initialise();
	}
	public class Foo : IInitialise {

		private Bar bar;

		public void Initialise() {
			DependencyManager dm = new DependencyManager();
			bar = dm["Bar"] as Bar;
		}

	}
If we add other dependencies to Foo then as long as the DependencyManager can return instances of them we have not greatly increased the coupling of Foo. This is a Good Thing�.

The DependencyManager, though, is coupled to most of the system. I don't imagine that these types will be directly re-usable so this probably doesn't matter too much. Anyway, we have most of our creational dependencies centralised in one place which makes it relatively easy to manage: change Bar's constructor and only the DependencyManager needs to change with it, not the other classes which actually use Bar.

The DepencencyManager usually has some external configuration file, defining how to create a Bar etc. If all this knowledge can be put into this file then DependencyManager actually becomes an uncoupled class and can be re-used. However, it is very open to mis-configuration.

All creators of Foo's have to know to call Initialise(). Thus most IoC-1 systems will use a container or factory type to create them. (Containers are also a current hot topic.)

IoC-2 aka Setter Dependency Injector

The creator of the Foo hands it a Bar:
	public class Foo {

		private Bar bar;

		public Bar Bar {
			set { bar = value; }
		}

	}
Very similar to IoC-1, save that it is less general and the creator has to know a) that a Foo must have a Bar and b) how to create a Bar. Again, this can be delegated to a container which may or may not have an external configuration.

IoC-3 aka Constructor Dependency Injector

In this version of IoC, Foo takes a Bar in its constructor:
	public class Foo {

		private Bar bar;

		public Foo (Bar bar) {
			this.bar = bar;
		}
	}
This is obviously safer that IoC-1 and IoC-2 as you just can't create a Foo without giving it its dependencies.

Sensible bit 1

Of these three, IoC-3 looks by far the safest and possibly the easiest. IoC-1 and IoC-2 both depend on users or creators of the class knowing that there is still work to be done on the instance after it is created, thus opening the possibility of not fully initialising an instance and using a badly-formed Foo; this will only be caught at run-time.
IoC-3 prevents improper creations at compile time.

Another option is to mix IoC-1 and IoC-3:
	public class Foo {

		private Bar bar;

		public Foo () {
			this.Initialise();
		}

		protected void Initialise() {
			DependencyManager dm = new DependencyManager();
			bar = dm["Bar"] as Bar;
		}

	}
This option seems to be missed out in the documents I can find. It does have drawbacks. Note that Initialise() is protected, so that inheriting classes can call it. Should it be virtual so that inheritors can put in their own implementations getting dependencies which they introduce? If so, there are technicalities about calling virtual methods from base-class constructors which can trip you up (in C# at any rate) unless you know what's going on. There are some subtleties here, so perhaps it better to stick with type 3 after all.

Excellent. We've reduced Foo's coupling and thus got a more maintainable and re-usable system.

Where shall we go for a drink?

Our Foo needs a Bar to do some or all of it's work. Fine, no problem. But which Bar?
There are two options:
  • the client doesn't care: it just wants Foo to do some work for it, in the course of which Foo needs a Bar - the client doesn't know that and doesn't care.
  • the client wants Foo to do some work on this specific Bar and no other
In the first case using IoC-3 makes the client dependant on Bar as well as Foo - not what we wanted at all: not only have we just moved the problem (which is how to create an instance of a class, remember) from Foo to it's client - no net gain - we have introduced an extra dependency on Bar to that Client - a net loss.

In the second case, the client already has a Bar and Foo would have to use IoC-2 or IoC-3 anyway, so not net loss, no net gain.

In either case, what if Foo is long-lived and only needs a Bar for a small part of its work - one method, say? Putting the Bar in as a member now links the Bar's lifetime to the Foo's. What if the Foo doesn't even need a Bar for what a particular client is going to ask it to do?

We have some problems here:
  • Foo may only want a transient Bar
  • the Client may not need to know about Bar's
The first is in fact easy: Foo creates its Bar when it needs it in the same way Foo's client creates the Foo - Foo is a client of Bar after all.
The second requires Foo to be created by a third-party: a Factory or a DependencyManager of some kind. Handing off Foo's creation this way goes a long way to solving these problems - and the original one as well.

Containers

These are the things which perform these creations. This solution is coming out of the Java world where the traditional containers have been pretty meaty things. 'Lightweight Containers' are what they are looking for. There are a number of frameworks of Lightweight Containers, including PicoContainer (where I got a lot of this information) where there are links to other implementations.

Pico looks an interesting framework. It relies on configuration files, as do all these types of container, and thus on Reflection to create objects of the correct type. There is a .NET port apparently, although the link on the Pico site is broken.

Container or Factory?

Factories solve these problems fine, as do Builders and the other GoF creational patterns.
If Foo always needs a specific Bar:
	public class FooFactory {
		public static Foo Foo(Bar bar) {
			return new Foo(bar);
		}
	}

If Foo always needs a Bar but it doesn't matter which one:
	public class FooFactory {
		public static Foo Foo() {
			return new Foo(new Bar());
		}
	}
What if Bar has its own dependencies?
	public class FooFactory {
		public static Foo Foo() {
			return new Foo(BarFactory.Bar());
		}
	}
You can see where this is going: we have a whole system of Factories calling each other. True, all the knowledge required is centralised but it's all hard-coded. If Bar doesn't need anything except itself (i.e. we are using return new Foo(new Bar());) what happens if Bar changes and now does need something? We now have to change all Factories which create a Bar to use a BarFactory. Far better to use a BarFactory from day one? Now you've got a Factory for just about every class in the system. I don't think that this is very sensible. This is one reason for these configuration-driven creational classes: add a dependency and no code changes are required. But.....

I only wanted a drink, Guv!

These containers may be 'Lightweight', but that's used relatively. They are not simple things (read the Pico site and look at what their containers do; imagine the source behind the example calls).

Are they a solution looking for a problem? Possibly. The Java world is full of frameworks which do just about anything you can image and some things which I can't ever imagine needing; and wherever there is one framework doing something you can bet that there are at least two others under development (like buses; see also the excellent BileBlog for a jaundiced view of the Java world).

Most of the time you can just walk into a bar, but if you're in the Antarctic you need to build some infrastructure first�

Return to top