Dependency Injection – Benefits of Using IoC Containers

dependency-injectioninversion-of-controlioc-containers

I've seen several recommend use of IoC containers in code. The motivation is simple. Take the following dependency injected code:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest(
        std::auto_ptr<Dependency> d = std::auto_ptr<Dependency>(new ConcreteDependency)
    ) : d_(d)
    {
    }
};


TEST(UnitUnderTest, Example)
{
    std::auto_ptr<Dependency> dep(new MockDependency);
    UnitUnderTest uut(dep);
    //Test here
}

Into:

class UnitUnderTest
{
    std::auto_ptr<Dependency> d_;
public:
    UnitUnderTest()
    {
        d_.reset(static_cast<Dependency *>(IocContainer::Get("Dependency")));
    }
};


TEST(UnitUnderTest, Example)
{
    UnitUnderTest uut;
    //Test here
}

//Config for IOC container normally
<Dependency>ConcreteDependency</Dependency>

//Config for IOC container for testing
<Dependency>MockDependency</Dependency>

(The above is hypothetical C++ example of course)

While I agree that this simplifies the interface of the class by removing the dependency constructor parameter, I think the cure is worse than the disease for a couple of reasons. First, and this is a big one for me, this makes your program dependent on an external configuration file. If you need single binary deployment, you simply cannot use these kinds of containers. The second issue is that the API is now weakly and worse, stringly typed. The evidence (in this hypothetical example) is the string argument to the IoC container, and the cast on the result.

So.. are there other benefits of using these kinds of containers or do I just disagree with those recommending the containers?

Best Answer

In a large application with many layers and lots of moving parts, it's the drawbacks that start to look pretty minor in comparison to the advantages.

The container does "simplify the interface" of the class, but it does so in a very important way. The container is a solution to the problem that dependency injection creates, which is the need to pass dependencies all over the place, down through object graphs and across functional areas. You have one small example here that has one dependency - what if this object had three dependencies, and the objects that depended on it had multiple objects that depended on them, and so on? Without a container, the objects at the top of those dependency chains end up becoming responsible for keeping track of all of the dependencies in the entire application.

There are different kinds of containers, as well. Not all of them are stringly typed, and not all of them require configuration files.

Related Topic