Monday, April 20, 2009

On using containers as objects

Have you heard of the magic of IoC containers? if not go out there and educate yourself. I remember the first time someone told me about spring, the usefulness of it went clear over my head. It was almost a year before I had the chance to use one, and that first discovery was a revelation.

In fact, after that life-changing experience I wound up on a project where I could not add a 3rd party container, and was so devastated that I wrote a lightweight container-like service locator/factory.

I've since gone on to other projects with different containers, and have on a number of occasions used a trick that has proven useful a few times over.

Before spilling the beans, I have to warn you that I always hide the container behind some home rolled class. This allows me to be container independent - I like wrapping all external dependencies.

This allows me to do something a little unorthodox: upon container initialization, I have the container add itself to the set of possible services. Concretely this means that components that need the container to do something a little more elaborate then just resolve dependencies, can fall back on using the container as a "pull"-base locator.

How is this useful?

This pattern has proven useful for a number of occasions where it was handy to be able to select a service implementation based on some runtime condition.

Consider the following fictitious example where we select different implementations IDosomething identified by some identifier:

    if (a.Value == "a")
        IDosomething something = container.Resolve("a");
    else if (a.Value == "b")
        IDosomething something = container.Resolve("b");
    ...
    something.Do(a);
or simplified as
    IDosomething something = container.Resolve(a.Value);
    something.Do(a);

Because the different implementations of IDosomething are built by the container, they are subject to all container controlled lifecycles, aspects and DI.

Now if we wanted to inject the dispatching to IDosomething to the services that need it, we could abstract out the dispatching service (FYI in C# with Castle's Windsor container):

    class SomethingDispatcher {
        private ObjectContainer container;
       
        public SomethingDispatcher(ObjectContainer container) {
            this.container = container;
        }

        public void Do(SomeObject a) {
            IDosomething something = container.Resolve(a.Value);
            something.Do(a);
        }
    }

This handy idea has served me for configurable event processors on a number of occasions. It also saves me the mess of configuring in detail the injection of each handler.

So how di I get the container in the container? With the following type of hack:

    class ObjectContainer {
        ObjectContainer() {
            this.container = ....
            this.container.Kernel.AddComponentInstance(this);
        }
        ...

In some cases it can be useful to specify qualified service IDs like "a.eventHandler" and "event-5633.eventProcessor". If this is the case, the dispatcher can take charge of building the qualified IDs it supports for example:

        string doerId = string.Format("{0}.eventHandler", a.Value);
and
        string eventId = string.Format("event-{0}.eventProcessot", eventCode);