4

Is it safe to say that a Container is the "program" or mechanism that manages IoC via DI, but it doesn't really change your initial design of DI to accomplish loose coupling?

In other words, if I want to achieve loose coupling, say for a Logger, using a Container doesn't change that. It just manages it in case I had a lot of dependencies to construct a class (less typing, more manageable, better Unit testing, etc.)

It won't change the fact that I have interfaces and contracts with ILogger or IDatabase, for example, correct?

//Assume I have to interfaces and two classes that implement them
Class DemoDI
{
    ILogger myLogger;
    IDatabase myDatabase;

    DemoDI(ILogger myLogger, IDatabase myDatabase)
    {
        this.myLogger = myLogger;
        this.myDatabase = myDatabase;
    }

    //Methods that do stuff with the logger and database
}

I'm asking if that wouldn't change, that design pattern. It's just that somewhere, (main?), I would (say with Unity)

ioc.RegisterType<ILogger MyLoggingClass>(new ContainerControlledLifetimeManager());
ioc.RegisterType<IDatabase MySQLDatabaseClass>; //transient by default

And, if MySQLDatabaseClass had,

interface IDatabaseConnection
{
    void GetConnection();
}
Class DataConnection : IDatabaseConnection
{

    public void GetConnection()
    {
        //Get a connection
    }

}
Class MySQLDatabaseClass
{
    DataConnection myConn;

    MySQLDatabaseClass(DataConnection myConn)
    {
        this.myConn = myConn;
        this.myConn.GetConnection();
    }
    //Do other things;


}

Then the Container would wire that up too, assuming I had a:

ioc.RegisterType<IDatabaseConnection, DataConnection>();

If not I'd have to do it all by hand. The container is the helper that makes it nice and neat and assembles it all.

Now, if I want to Unit test the database class I would just have to adjust my container:

ioc.RegisterType<IDatabase MyMockedUpMySQLDatabaseClass>; //transient by default

Do I understand the purpose of an IoC Container correctly? Hopefully, I didn't get too lost in my dependencies.

7
  • 3
    If you're Doing It Right™, and it seems you are, then no; using an IoC container (or not) has no impact on the design of your code.
    – RubberDuck
    Commented Dec 22, 2016 at 22:32
  • 1
    Container won't change your design, but container itself doesn't imply auto wiring and mapping concrete classes to inetrfaces. You might be pushed into wrong decisions by these magic tricks (would you reject stupid decorator because it requires different approach?). A tendency to smear composition all over the code (annotations) might be unpleasant expierience either as your controll over it also becomes "inverted".
    – shudder
    Commented Dec 22, 2016 at 23:40
  • 2
    To concur with RubberDuck, if you're doing it right, a container changes nothing about the design of your code. But it's entirely possible to abuse a container to more tightly couple your application.
    – mgw854
    Commented Dec 23, 2016 at 0:45
  • @mgw854 I was wondering about that as well. That configuration looked just as hardcoded as the other, at times.
    – johnny
    Commented Dec 23, 2016 at 2:49
  • 1
    Hard to recall something concrete - its sort of compiled source product. Though I can point you out to these two I came across recently: Mark Seemann - When to use DI container and Greg Young - 8 Lines of Code
    – shudder
    Commented Dec 23, 2016 at 10:08

1 Answer 1

6

Is it safe to say that a Container is the "program" or mechanism that manages IoC via DI, but it doesn't really change your initial design of DI to accomplish loose coupling?

IoC and DI will change any design that didn't previously follow them. Using a container shouldn't change your design but it often does. Some containers demand you spread knowledge of the container throughout your code base. You end up trading one one set of dependencies for another. You shouldn't be able to look at a class and tell what container is involved. If you can, well now you're dependent on that container.

IoC and DI do not require a management container. You can manage them best by understanding what they are rather than expecting a container to do your thinking. You can manage them with a container but that's your choice.

Foo foo = new Foo( new Bar() );

That right there is a dependency injection. Foo depends on Bar, or at least some kind of Bar like thing. Foo can't exist without it. Bar is a dependency. Since Bar is being passed to Foo, Bar is a dependency that's been injected.

IoC is a complicated way to say: don't hard code knowledge of an implementation. If Foo built it's own Bar, Foo would be hard coded to Bar and Foo couldn't accept new kinds of Bar but if Foo doesn't know about Bar, just an interface, then Bar can be changed without touching Foo.

There are many way's to not hard code a dependency (follow IoC):

  • Factory pattern
  • Service locator pattern
  • Dependency injection,
  • Constructor injection
  • Parameter injection
  • Setter injection
  • Interface injection
  • Contextualized lookup
  • Template method design pattern
  • Strategy design pattern

You can do this stuff in a container. You can do it in construction code. You can do it in main.

Wherever you do it, please don't mix this construction code with behavior code. Hard wiring together stuff the moment you feel like it creates the mess that started this overblown container movement in the first place. It's a real problem. The best solution is to understand that you can fix it yourself.

3
  • Doesn't the container become useful when there are many dependencies for Foo and many for Bar? I have the same thoughts about the Container. There is something in there I just don't like, like an ORM, but I can't say I won't use them. I do. I have to think on IoC Containers a bit.
    – johnny
    Commented Dec 23, 2016 at 16:30
  • 2
    IoC Containers are often abused to impose an architecture. It's a poor team that needs that. Sure Java makes construction a pain because it doesn't have named parameters. The josh bloch builder simulates them to take care of that. Hash tables let me find instances based on strings just fine. And I know how to not mix behavior classes with construction classes without being forced to do construction in xml. But sure, I can find a use for a container. They can automatically resolve the cyclic dependencies we shouldn't have designed in the first place. Whee... Fun... Commented Dec 23, 2016 at 18:02
  • You should add this to your answer.
    – johnny
    Commented Dec 23, 2016 at 18:09

Your Answer

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