0

I am trying to utilize dependency injection technique in an application but getting confused if this context require DI or not..

Consider an interface:

public class ICardsHub {
    public T GetPlayersList<T>();
}

and its implementation:

public class GenericHub : ICardsHub {

    LANPlayers LANPlayers;
    WaNPlayers WANPlayers;
    bool AlgorithmsUseTildainLambdas=false;

    public GenericHub(LANPlayers _LANPlayers, WaNPlayers _WANPlayers, 
                           bool algorithmsUseTildainLambdas=false) {
        LANPlayers = _LANPlayers;
        WANPlayers = _WANPlayers;
        AlgorithmsUseTildainLambdas = algorithmsUseTildainLambdas;
    }

    public T GetPlayersList<T>() {
        ....
    }

}

and the driver class is supposed to do something like:

ICardsHub _ifCards = new GenericHub(_LANPlayers, _WANPlayers);
listOfPlayers = _ifCards.GetPlayersList<List<string>>();

Now, we have two more implementations of ICardsHub; RedHub and BlackHub which are instantiated later in the driver class.

Questions

  1. How can the Unity IoC/DI benefit this scenario?
  2. If striping out method parameters from the interface and injecting them to overload constructor solves the problem, then what is the suitable scenario for DI container usage?
Annie
  • 3,090
  • 9
  • 36
  • 74
  • Can you elaborate what is the "problem" your question 2 refers to? – Srikanth Venugopalan Mar 30 '13 at 02:16
  • 2
    @Annie: DI is applicable in pretty much any context. The mistake you seem to make is the same as I did when I started getting into this - you try to arbitrarily throw a technique at code hoping it will somehow help. DI is nothing that can make code better on its own; it is only a means to an end, and you have to know the end you want to achieve before you can determine the means that you need. What is the problem you are trying to solve? – TeaDrivenDev Mar 30 '13 at 03:00
  • @GCATNM, thanks for the insight. I need to change the behavior of program which depends on sub-class selection. – Annie Mar 30 '13 at 07:48
  • For what reason and by what criteria does that subclass selection happen? With DI, object instantiation should generally happen as early as possible, usually in the composition root. If the application doesn't have that information at that point, you would need to use techniques like the Factory pattern as described below by @Devesh. – TeaDrivenDev Mar 30 '13 at 13:13
  • There is a whole lot of wrong information here. At the top the root you have IoC, and then two implementation of the pattern, DI, and Service Locator. On top of that you can inject your dependencies in the constructor or in the properties. DI object instantiation should not in any way happen as early as possible, what would the point be? What happens is that the IoC container maps the list of types that will be used in the DI later, but it does not instantiate any object until it is necessary. – MeTitus Mar 30 '13 at 14:18
  • Service Locator is hardly ever viable: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ . It introduces tight coupling (to the locator) and obscures the API and by that also makes testing more cumbersome. As for DI instantiation, of course instances aren't created before they are needed to inject them, but the goal is to do so as far up in the program's flow (or object graph) as that decision can be made. – TeaDrivenDev Mar 30 '13 at 14:35

3 Answers3

2

DI benefits the code for easy to maintain and easy to switch over to new implementation. I agree overloaded constructor will serve the purpose but if you have many and many dependency , still we have to make sure manually and making the code change to effectively going to each place and change it by hand and sometime you can miss some of them. having a central location will help easy to maintain. This is the reason DI is not suggested for smaller project but good sizeable projects. I do not think DI purpose to solve TDD but better maintainability and easy switching over to new implementation of classes . Example today you are using SQL SERVER as your Database , and tomorrow you change to NOSQL . One place change in class name will make sure in all the places all the code interacting with DB will work fine. TDD is one of the example

Devesh
  • 4,500
  • 1
  • 17
  • 28
  • Devesh, thanks for your reply. I would be changing the behavior of program as its behavior depends upon sub class selection. But if we consider the other pattern, I can setup a base class and use the ICardHub in that and then inherit the driver (and other program classes) from base. That would also improve manageability of dependencies (centralized control). – Annie Mar 30 '13 at 07:17
  • Why do not you try then Factory design pattern ? DI is does not try to achieve or solve any business or application requirement but rather it try to give your system more flexibility from the changes that may do in future and decoupling from any external or internal dependency which may change. For example you may have external email service , which you may change down the line to change , DI will help easy and smooth migration with minimum change. – Devesh Mar 30 '13 at 08:07
1

The primary motive of DI is testability, IMHO. So, if you look outside the testing paradigm, there might be some confusion.

In the example you've described, I see that ICardsHub defines a contract for the implementation of GenericHub, RedHub and BlackHub.

Now each of these implementation will have some logic that makes it different and thus the need for different classes to exist.

In order to test these classes (their responsibility is unique), there are some steps to be performed before these classes can perform their jobs and there might be some post these steps.

The scope of the test for this class is to ensure that Given the "pre" steps are error free, an action made by this class will have error-free output for the "post" steps to consume.

With this in mind, dependency injection allows us to

  1. easily assume the preconditions (i.e. inject mock objects, with the assumptions setup)
  2. perform an action (responsibility of this class)
  3. Verify the output.

And btw, your implementation should inject Interfaces rather than concrete type. Something like -

ILANPlayers LANPlayers;
IWaNPlayers WANPlayers;
bool AlgorithmsUseTildainLambdas=false;

public GenericHub(ILANPlayers _LANPlayers, IWaNPlayers _WANPlayers, 
                       bool algorithmsUseTildainLambdas=false) {
    LANPlayers = _LANPlayers;
    WANPlayers = _WANPlayers;
    AlgorithmsUseTildainLambdas = algorithmsUseTildainLambdas;
} 

So that in a test you can mock ILanPlayers and IWanPlayers which are essentially mock implementation of these types.

Srikanth Venugopalan
  • 9,011
  • 3
  • 36
  • 76
0

In general you only use DI to help you perform unit testing. You should code against interfaces so, by using DI you can mock your components easily.

In your scenario you will have some client classes using an implementation of the ICardHub interface, the question now is, will any of those implementation perform database operations or any other external usage, if not you're most likely better of without using DI.

If you still want to use DI, go with AutoFac instead, it is IMO easy to work with.

If you have some piece of code that you think you can create a "library" off, that is a good candidate for DI. You have to think about these components as providers and DI in general is nothing new. DI just removes the responsibility of your application from creating the instances of the providers it needs, it´s the DI container doing it, and your application works with interfaces only.

Here is an Example:

  • Without DI

    IDatabase database = new SqlServer();
    
  • With DI

    IDatabase database = DIContainer.Get<IDatabase>();
    

As you can see, even though your application will be using the SqlServer database it knows nothing about that. Yes you have to register that type in the DI container but you do it only once, thus if you later decide to change to other implementations it is quite easy.

MeTitus
  • 3,390
  • 2
  • 25
  • 49
  • "In general you only use DI to help you perform unit testing." This is absolutely not true. DI is a means to not only make your code testable (although it is mandatory for that), but also maintainable, adaptable and evolvable. If it was only about testability, I doubt there would be so much effort put into (and whole books written about) it. – TeaDrivenDev Mar 30 '13 at 02:38
  • Then search about how it is being used ;) here for example: http://stackoverflow.com/questions/1580641/when-to-use-dependency-injection. You don't need IoC to achieve low coupling, maintainable and scalable code. Maybe have a read about GRASP, SOLID, Gang of 4... – MeTitus Mar 30 '13 at 02:45
  • @GCATNM - the statement hints about testability as a use case for DI, not the only reason for doing DI. Maintainability, adaptability and evolution have been around in software much before DI became popular, these mandate good design in general. – Srikanth Venugopalan Mar 30 '13 at 14:43
  • 1
    They do, but now that DI is well-understood and there are excellent technical solutions to build upon (especially in .NET), the majority of applications will clearly benefit from it if applied correctly, so it doesn't make much sense to consider it optional anymore. I never said it was the only way of achieving those goals. Also, he _did_ say it was the only reason, as I quoted in my first comment, and that is clearly wrong. – TeaDrivenDev Mar 30 '13 at 15:39
  • 1
    Nop I never did. I said in general. – MeTitus Mar 30 '13 at 16:14