Subscribe to Sergio Tapia - Lost in the GC.        RSS Feed
****- 1 Votes

What is Dependency Injection, and why should I care?

Icon 13 Comments
I'm going to be using C# for this article, but the principle is what is important. Focus on the principle behind the code. :)

Imagine you get an email one morning, Valve Software wants you to prototype their next MUD game. It's going to be a dungeon crawler RPG where you will have warriors, weapons, spells, the works.

"Ok, you think to yourself. I can do this! :)"

"Great! First I need you to create our Warrior class and give him a sword just to start out."

So, you create a Warrior class:

public class Warrior
{
    Sword sword;

    public Warrior()
    {
        sword = new Sword();
    }

    public void Attack(string target)
    {
        sword.Hit(target);
    }
}


Then you create the Sword class:

public class Sword
{
    public void Hit(string target)
    {
        Console.WriteLine("You slice {0} in half!", target);
    }
}



Finally, this is how you would use it:

static void Main(string[] args)
{
    Warrior gustaf = new Warrior();
    gustaf.Attack("Orc");

    Console.Read();
}



And as expected, it works. "Send my check in the mail", you think. But hold on! Valve calls you the following morning and tells you that the producer wants another weapon for the warrior. They want to give the warrior an axe.

"No problem, Mr. Business Man Guy - I'll get right on that.", you say.

Let's create another class for the Axe then:

public class Axe
{
    public void Hit(string target)
    {
        Console.WriteLine("You smash the puny {0} with your mighty axe!", target);
    }
}



How can we tell our Warrior to use this...hm. Let's try this:

public class Warrior
{
    Sword sword;
    Axe axe;

    public Warrior()
    {
        sword = new Sword();
        axe = new Axe();
    }

    public void Attack(string target)
    {
        sword.Hit(target);
    }
}



But wait - how do we know what weapon the warrior is supposed to use? :(

What about this, we can use a boolean attribute and use that to decide whether we use the sword or the axe.

public class Warrior
{
    Sword sword;
    Axe axe;
    private bool _useSword;

    public Warrior(bool useSword)
    {
        sword = new Sword();
        axe = new Axe();
        _useSword = useSword;
    }

    public void Attack(string target)
    {
        if (_useSword)
            sword.Hit(target);
        else
            axe.Hit(target);
    }
}



So far so good, you can practically smell the check in the mail. You commit the code to your repository and you get an email 20 minutes later from the Bossman.

"Are you sure you thought this through? What are you going to do when we decide the warrior will have another weapon and another and another?"

When you coded as we just did above, you acquire a lot of technical debt. Stuff you're going to be held accountable for in the future and you will have to face it.

Let's use Dependency Injection to improve this code and make sure Valve pays us.

First, lets create an interface called IWeapon. This will have a single method, Hit.

public interface IWeapon
{
    void Hit(string target);
}



Now let's modify our Sword and Axe class:

public class Sword : IWeapon
{
    public void Hit(string target)
    {
        Console.WriteLine("You slice {0} in half!", target);
    }
}

public class Axe : IWeapon
{
    public void Hit(string target)
    {
        Console.WriteLine("You smash the puny {0} with your mighty axe!", target);
    }
}



Great, our two weapons are implementing the IWeapon interface.

Lets modify the Warrior class to take advantage of this chage:

public class Warrior
{
    private IWeapon _weapon;

    public Warrior(IWeapon weapon)
    {
        _weapon = weapon;
    }

    public void Attack(string target)
    {
        _weapon.Hit(target);
    }
}


Notice how cleaner the code is and how easily we can inject the dependency. Here's how we would use this:

static void Main(string[] args)
{
    Warrior gustaf = new Warrior(new Axe());
    gustaf.Attack("Orc");

    Console.Read();
}


Since we are using interfaces instead of concrete objects, we no longer need specific object types in our class. In the constructor of the Warrior class, we can inject whatever concrete implementation we need.

"Sergio, what in the hell does all this mean? I'm still waiting for the punchline."

The benefit of Dependency Injection being able to expand an existing system without the need for modification on our part. Since we use interfaces, implementation details are not necessary so long as they follow the interfaces contract.

In the next article, I'll look into Ninject and how to use this to automatically inject dependencies without the need to wire things up manually.

13 Comments On This Entry

Page 1 of 1

xheartonfire43x Icon

07 March 2011 - 12:08 PM
Really nice example of dependency injection. I have heard the phrase many times before, but never really understood it at all.
0

diego_pmc Icon

07 March 2011 - 12:57 PM
Are you sure this is DI? I was under the impression DI meant asking directly for the objects you need (as opposed to asking for a factory and building the objects yourself), which reduces decoupling between the class and the factory, which means you can create the needed components as you see fit. Did I misunderstand DI?
0

Sergio Tapia Icon

07 March 2011 - 01:10 PM
100% sure. :)

In a single sentence, I would say dependency injection is setting all your object dependencies through the object constructor.

If you'd like to read more about the subject, check out:
http://stackoverflow...dency-injection
0

Dormilich Icon

07 March 2011 - 04:06 PM
a good example of "code against an Interface, not an Implementation"
0

BobRodes Icon

07 March 2011 - 06:01 PM
Excellent example, Sergio, very concise and to the point. I've never been able, however, to understand what the difference between dependency injection and polymorphism is. Some people say that this is a "more flexible" version of polymorphism or whatever, but yours is exactly analogous to the example of polymorphism (I actually have a T. Rex and a flea that both move and bite) that I used when I was teaching this stuff about 10 years ago. Seemed to me at the time that Fowler was just finding new words for old ideas when he started talking about dependency injection back in 2004.

Can you shed some light on this? Perhaps there are some examples of polymorphism that don't conform to the dependency injection pattern?
0

BobRodes Icon

07 March 2011 - 06:13 PM
Great example, Sergio. Very concise and to the point.

However, I've never been able to see why Fowler wasn't just using new words for old ideas when he started talking about this back in 04 or so. I've used an example in my OOAD classes that seems analogous to yours (I use an iAnimal and a TRex and a Flea, with a Move and a Bite).

However, as I write this, I get to thinking. My class example doesn't have an association with it as yours does. Your polymorphed weapon has a warrior with it, and maybe it's the fact of the association that makes it a dependency injection. For example, if you had a Toon class with an Attack method, implemented by your warrior and, say, a mage, both of whom attacked quite differently, that might be an example of polymorphism but not of dependency injection?
1

Sergio Tapia Icon

07 March 2011 - 06:23 PM
When you use polymorphism in C#, you're creating a base class - and creating other classes basing them on the primary class.

For example:

Shape
Circle : Shape
Square: Shape
Triangle : Shape


You get all the baggage of the base class, and using the virtual keyword you can allow child classes to implement their own 'vision' of what methodX might do.

I just tried it out using a base class Shape, and many children classes and the principle is the same. I prefer using interfaces because I see them as contracts, meaning, [b]"I don't care how you do this, but make sure you do it.".

Using a base class seems to be a good idea if you want the children to share some commonalities.

Using your example of a mage, I would create an IPlayerClass interface, and use that for warriors, mages, rogues, etc.
0

dorknexus Icon

08 March 2011 - 10:26 AM
A large portion of dependency injection is in the "program to an interface" part. That is indeed just polymorphism. However, you can program to an interface and still have a class go and fetch its dependencies from a factory or something like that. Dependency injection is specifically program to generic interfaces and providing dependencies to a class rather than having the class go and fetch its dependencies manually. DI is also generally aided by some sort of automated framework.
0

BobRodes Icon

08 March 2011 - 05:41 PM
Ok, I think I understand what you're saying, Dark, but can you explain what it is in Sergio's example that makes that dependency injection and not just polymorphism? That would help me a lot.
0

Sergio Tapia Icon

08 March 2011 - 06:17 PM
Dependancy injection is a big word for a very simple concept. Basically it's giving assigning the objects attributes through its constructor.

See the Wikipedia link for an example of polymorphism. That is not dependency injection, because we aren't assigning any attributes via the constructor.
http://en.wikipedia....rogramming#C.23

For it to be DI, you have:

IAnimal _iAnimal;

public Animal(IAnimal animalType)
{
    _iAnimal = animalType;
}

public void Speak()
{
    _iAnimal.Speak();
}


Notice how we're assigning behavior via the constructor. In a plain polymorphism example, such as the Wikipedia one, we do not assign behavior, but instantiate concrete types.
0

Ninjato Icon

10 March 2011 - 06:43 AM
a good example about dependency injection thanks
0

raziel_ Icon

10 March 2011 - 09:47 AM
i always think that DI is injecting DLL in some program by replacing one that he use. :D
0

Dormilich Icon

11 March 2011 - 05:06 AM
not sure where I picked that link up, though its worth a read: Inversion of Control & Dependency Injection
0
Page 1 of 1

Trackbacks for this entry [ Trackback URL ]

There are no Trackbacks for this entry

0 user(s) viewing

0 Guests
0 member(s)
0 anonymous member(s)

About Me

Posted Image


Bienvenidos! I'm a USA ex-pat living in Bolivia for the past 10 years. Web development is my forte with a heavy lean for usability and optimization. I'm fluent in both English and Spanish. I guest write for the popular Python website Python Central. Visit my website.

Categories