Dependency Injection what´s the big improvement?
Asked Answered
B

3

10

Currently I'm trying to understand dependency injection better and I'm using asp.net MVC to work with it. You might see some other related questions from me ;)

Alright, I'll start with an example controller (of an example Contacts Manager asp.net MVC application)

public class ContactsController{

  ContactsManagerDb _db;

  public ContactsController(){

    _db = ContactsManagerDb();

  } 

  //...Actions here
}

Allright, awesome that's working. My actions can all use the database for CRUD actions. Now I've decided I wanted to add unit testing, and I've added another contructor to mock a database

public class ContactsController{

  IContactsManagerDb _db;

  public ContactsController(){

    _db = ContactsManagerDb();

  }

  public ContactsController(IContactsManagerDb db){
    _db = db;
  }

  //...Actions here
}

Awesome, that's working to, in my unit tests I can create my own implementation of the IContactsManagerDb and unit test my controller.

Now, people usually make the following decision (and here is my actual question), get rid of the empty controller, and use dependency injection to define what implementation to use.

So using StructureMap I've added the following injection rule:

x.For<IContactsManagerDb>().Use<ContactsManagerDb>();

And ofcourse in my Testing Project I'm using a different IContactsManagerDb implementation.

x.For<IContactsManagerDb>().Use<MyTestingContactsManagerDb>();

But my question is, **What problem have I solved or what have I simplified by using dependency injection in this specific case"

I fail to see any practical use of it now, I understand the HOW but not the WHY? What's the use of this? Can anyone add to this project perhaps, make an example how this is more practical and useful?

Bedstead answered 8/10, 2011 at 20:26 Comment(4)
Could you unit test that code before you added the injected object?Advocaat
Yes right? Because I overloaded the constructor, and just insert it manually with my MyTestinContactsManagerDbBedstead
So you made the concrete implementation depend on a test class? Let me rephrase that, you coupled your class-under-test with a class-used-for-testing? This is what you get with injection, you decouple classes, make them independent.Advocaat
Ah yeah ofcourse, you're right. That's indeed stupid :PBedstead
B
10

The first example is not unit testable, so it is not good as it is creating a strong coupling between the different layers of your application and makes them less reusable. The second example is called poor man dependency injection. It's also discussed here.

What is wrong with poor man dependency injection is that the code is not autodocumenting. It doesn't state its intent to the consumer. A consumer sees this code and he could easily call the default constructor without passing any argument, whereas if there was no default constructor it would have immediately been clear that this class absolutely requires some contract to be passed to its constructor in order to function normally. And it is really not to the class to decide which specific implementation to choose. It is up to the consumer of this class.

Backgammon answered 8/10, 2011 at 20:27 Comment(4)
I don't like this way of saying DI / IOC is for unit testing. In fact, if it is only for unit testing, you should not be doing it.Boxwood
@manojlds, I absolutely agree with you. The greatest benefit of DI/IOC is to achieve week coupling between the layers of the code making them more reusable in different contexts/applications. Unit testing is just an additional benefit that you get from this week coupling as it allows you to test those layers in isolation.Backgammon
Seriously Darin, I've been struggling with Dependency Injection for quite some time now. Your explanation and the website you've linked to describe it very clearly and for the first time I finally have a feeling I'm starting grasp it! You really deserve my thanks!!!!Bedstead
You also have to add the control over the object life time. Using poor man DI is by far not that comfortable than using an IoC container.Datary
S
5

Dependency injection is useful for 3 main reasons :

  • It is a method of decoupling interfaces and implementations.
  • It is good for reducing the amount of boiler plate / factory methods in an application.
  • It increases the modularity of packages.

As an example - consider the Unit test which required access to a class, defined as an interface. In many cases, a unit test for an interface would have to invoke implementations of that interface -- thus if an implementation changed, so would the unit test. However, with DI, you could "inject" an interface's implementation at run time into a unit test using the injection API - so that changes to implementations only have to be handled by the injection framework, not by individual classes that use those implementations.

Another example is in the web world : Consider the coupling between service providers and service definitions. If a particular component needs access to a service - it is better to design to the interface than to a particular implementation of that service. Injection enables such design, again, by allowing you to dynamically add dependencies by referencing your injection framework.

Thus, the various couplings of classes to one another are moved out of factories and individual classes, and dealt with in a uniform, abstract, reusable, and easily-maintained manner when one has a good DI framework. The best tutorials on DI that I have seen are on Google's Guice tutorials, available on YouTube. Although these are not the same as your particular technology, the principles are identical.

Slenderize answered 8/10, 2011 at 20:36 Comment(1)
I think that your answer (as well as the OP's question) are confusing the DI pattern and the use of a DI framework.Rosinweed
H
0

First, your example won't compile. var _db; is not a valid statement because the type of the variable has to be inferred at declaration.

You could do var _db = new ContactsManagerDb();, but then your second constructor won't compile because you're trying to assign an IContactsManagerDb to an instance of ContactsManagerDb.

You could change it to IContactsManagerDb _db;, and then make sure that ContactsManagerDb derives from IContactsManagerDb, but then that makes your first constructor irrelvant. You have to have the constructor that takes the interface argument anyways, so why not just use it all the time?

Dependency Injection is all about removing dependancies from the classes themselves. ContactsController doesn't need to know about ContactsManagerDb in order to use IContactsManagerDb to access the Contacts Manager.

Hustings answered 8/10, 2011 at 20:51 Comment(1)
Ah yeah sorry you're right about that. I've changed my post, I wrote it wrong when trying to simplify the situation. Thanks for pointing that out/Bedstead

© 2022 - 2024 — McMap. All rights reserved.