17

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?

1
  • 1
    The sample code looks like a really bad example of an IoC implementation. I'm only familiar with C# but surely there is a way to have constructor injection and programmatical configuration in C++ as well?
    – rmac
    Commented Sep 3, 2011 at 13:19

3 Answers 3

12

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.

11
  • 3
    But a large project makes the problems I already mentioned worse. If the project is large, the configuration file becomes a huge dependency magnet itself, and it becomes even easier to have one typo lead to undefined behavior at runtime. (i.e. having a typo in the config file would cause the cast to cause undefined behavior if the wrong type gets returned). As for dependencies of dependencies, those don't matter here. Either the constructor takes care of making them, or the test is going to be mocking out the top level dependency. Commented Feb 22, 2011 at 18:06
  • ... Continued ... When the program isn't being tested, the default concrete dependency gets instantiated at each step. W.r.t. other kinds of containers, do you have some examples? Commented Feb 22, 2011 at 18:07
  • 4
    TBH I don't have tons of experience with DI implementations, but take a look at MEF on .NET, which can be but doesn't have to be stringly typed, has no config file, and concrete implementations of interfaces are "registered" on the classes itself. BTW, when you say: "the constructor takes care of making them" - if that's what you're doing (aka "poor man's constructor injection"), then you don't need a container. The advantage of a container over doing that is that the container centralizes information about all those dependencies.
    – nlawalker
    Commented Feb 22, 2011 at 21:01
  • +1 for that last comment -- the last sentence there is the answer :) Commented Feb 23, 2011 at 2:17
  • 1
    Great answer that helped me grok the whole point. The point isn't just simplifying the boilerplate, but allowing the elements at the top of the dependency chain to be just as naïve as the elements at the bottom. Commented Mar 25, 2016 at 17:50
4

The Guice IoC framework from Java do not rely on a configuration file but on configuration code. This means that the configuration is code no different from the code making up your actual application, and can be refactored etc.

I believe that Guice is the Java IoC framework which finally got configuration right.

2
  • Are there any similar examples for C++? Commented Feb 22, 2011 at 20:58
  • @Billy, I am not familiar enough with C++ to be able to say.
    – user1249
    Commented Feb 22, 2011 at 21:56
0

This great SO answer by Ben Scheirman details some code examples in C#; some advantages of IoC containers (DI) being:

  • Your dependencies chain can become nested, and it quickly becomes unwieldy to wire them up manually.
  • Enables use of Aspect oriented programming.
  • Declarative & nested database transactions.
  • Declarative & nested Unit of work.
  • Logging.
  • Pre/Post conditions (Design by Contract).
2
  • 1
    I don't see how any of those things can't be implemented with simple constructor injection. Commented Apr 17, 2012 at 17:59
  • With a good design, constructor injection or another method may be enough for you; the advantages of these IoC containers might be only in specific cases. The example given with INotifyPropertyChanged in a WPF project was one such example. Commented Apr 18, 2012 at 0:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.