Depending on Injections

Dependency Injection is a new programming tactic used by a lot of M-V-VM and M-V-C frameworks. It allows you to “configure” how objects are created and used, relying on a config file to determine what concrete objects are used for dependencies in your application. There’s a lot of neat uses for this, from client-specific deployments to environment-based caching and tracing.

The main way this works is by taking advantage of the Factory pattern. Objects are provided through a Factory that reads an XML config file behind the scenes and uses that information to instantiate objects on the fly. Let’s look at a before-and-after example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ExampleModel
{
    public IProductProvider ProductProvider { get; set; }

    public ExampleModel(int argument)
    {
        if(argument == 1)
            this.ProductProvider = new ConcreteProductProvider1();
        else if(argument == 2)
            this.ProductProvider = new ConcreteProductProvider2();
        else
            this.ProductProvider = new DefaultProductProvider();
    }
}

//Constructor
ExampleModel em = new ExampleModel(1);

This is the old way – we have a dependency on a provider object, and we instantiate it in the constructor based on an argument. There’s nothing overly wrong with this, but as the possible argument values increase, it gets more and more unmaintainable – 15 possible providers means a 15-part if statement. Not to mention if you need to change anything, you have to recompile. Here’s the new way:

1
2
3
4
5
6
7
public class ExampleModel
{
    public IProductProvider ProductProvider { get; set; }
}

//Constructor
ExampleModel em = new ExampleModel();

That’s it! Actually, just kidding, there’s that XML config file we talked about earlier as well:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- this example uses the spring framework, 
  but other frameworks follow a similar pattern -->
<objects xmlns="http://www.springframework.net">
    <object name="ExampleModel"
            singleton="false"
            type="ExampleModel, IQ.Core.Models">
        <property name="ProductProvider">
            <ref object="ConcreteProductProvider"/>
        </property>
    </object>
    <object name="ConcreteProductProvider"
            singleton="false"
            type="ConcreteProductProvider1, IQ.Core.Providers">
    </object>
</objects>

Using this config file, the DependencyInjector finds a matching concrete class based on the type name, and instantiates it. Now, if we need to change what provider we use, we don’t have to recompile anything – we just change a config file setting. Which is easy enough to do in a deployment/build script. You can also use this for any property, including value types (set specific strings or numbers based on your config file).

Comments