views:

723

answers:

8

Can someone explain to me the advantages of using an IOC container over simply hardcoding the default implementation into a default constructor?

In other words, what is wrong about this code?

public class MyClass
{
    private IMyInterface _myInterface;

    public MyClass()
    {
        _myInterface = new DefaultMyInterface();
    }

    public MyClass(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
}

As far as I can tell, this class supports constructor injection enough so unit testing and mocking is easily done. In addition to which, the default constructor removes the computational overhead of the IOC container (not to mention the whole process is a lot more transparent).

The only benefits i can see to using an IOC container is if you need to switch out the implementation of your interfaces frequently. Am I missing something?

+9  A: 

Idea of IoC is to delegate part of your component functionality to other part of the system. In IoC world you have components that don't know about each other. You example violates this, you're creating tight coupling between MyClass and some implementation of IMyInterface. Main idea is that your component has no knowledge on (and shouldn't have) how it would be used. In your example component makes some assumptions about it's use.

Actually this approach can rights for living, but mixing IoC and explicit objects initialization is not a good practice IMO.

IoC gives you loose coupling (-> late binding) for the price of code clarity. When you add additional behavior it makes things even more complicated and can lead to bugs when some component can potentially receive object with unwanted\unpredicted behavior.

aku
A: 

I don't see why your technique of hardcoding the default implementation could not be used together with an IOC container. Just, the dependencies you don't specify in the configuration would take the default implementation.

Or am I missing something?

Sergio Acosta
A: 

One reason you might want to use an IOC Container would be to facilitate late configuration of your software.

Say, for instance, you provide several implementations of a particular interface - the customer (or your professional services team) can decide which one to use by modifying the IOC configuration file.

Seb Rose
+3  A: 

Pick a side :)

In short IOC is recommended. The problem with the code is that I cannot swap out the default implementation of the dependency without recompiling the code as you have stated at the end. IOC allows you to change the configuration or composition of your object in an external file without recompilation.
IOC takes over the "construction and assembly" responsibility from the rest of the code. The purpose of IOC is not to make your code testable... it is a pleasant side-effect. (Just like TDDed code leads to better design)

Gishu
+1  A: 

Besides loose coupling, an IoC will reduce code duplication. When you use an IoC and you want to change the default implementation of your interface, you have to change it at only one place. When you use default contructors to inject the default implementation, you have to change it everywhere the interface is used.

Paco
+3  A: 

There is nothing wrong with this code and you can still use it with Dependency Injection frameworks like Spring and Guice.

Many developers see Spring's XML configuration file as an advantage over wiring dependencies within code as you can switch implementations without needing a compilation step. This benefit actually is realized in situations where you already have several implementations compiled in your class path and you want to choose the implementation at deployment time. You can imagine a situation where a component is provided by a third party after deployment. Similarly there can be a case when you want to ship additional implementations as a patch after deployment.

But not all DI frameworks use XML configuration. Google Guice for example have Modules written as Java classes that must be compiled like any other java class.

So what is the advantage of DI if you even need a compilation step? This takes us back to your original question. I can see following advantages:

  1. Standard approach to DI throughout application.
  2. Configuration neatly separated out from other logic.
  3. Ability to inject proxies. Spring for example allows you to do declarative Transaction handling by injecting proxies instead of your implementation
  4. Easier re-use of configuration logic. When you use DI extensively, you will see a complex tree of dependencies evolving over time. Managing it without a clearly separated out configuration layer and framework support can be a nightmare. DI frameworks make it easy to re-use configuration logic through inheritance and other means.
Tahir Akhtar
+1  A: 

In addition to the other comments, one could argue the DRY (Do Not Repeat Yourself) principle in these cases. It's redudnant to have to put that default construction code in every class. It's also introducign special case handling where there doesn't need to be any.

Glenn Block
+1  A: 

The only concern I have is (1) if your default service dependency itself has another / secondary service dependency (and so on...your DefaultMyInterface depends on ILogger) and (2) you need to isolate the first service dependency from the second (need to test DefaultMyInterface with a stub ILogger). In that case you evidently will need to lose the default "new DefaultMyInterface" and instead do one of: (1) pure dependency injection or (2) service locator or (3) container.BuildUp(new DefaultMyInterface());

Some of the concerns other posters listed might not be fair to your question. You were not asking about multiple "production" implementations. You are asking about unit testing. In the case of unit tesing your approach, with my first caveat stated, seems legitimate; I too would consider using it in simple unit test cases.

Likewise, a couple responders expressed concern over repititiousness. I don't like repitition either, but if (1) your default implementation really is your default (YAGNI: you don't have plans on changing the default) and (2) you don't believe the first caveat I stated applies and (3) prefer the simpler code approach you've shared, then I don't think this particular form of repitition is an issue.

Brent Arias