Dependency Injection – How to Know When to Use It

dependency-injectionobject-oriented-designsingle-responsibility

The question might sound a little weird, and I guess it is. I'm came up with the question while browsing through some design patterns. I came to the notorious state / strategy pattern and I came up with this code:

public class Account
{
    public double Balance { get; private set; }

    private IAccountState state;

    public Account()
    {
        state = new ActiveAccountState();
    }

    public void Deposit(double number)
    {
        state = state.Deposit(() => Balance += number);
    }

    public void Withdraw(double number)
    {
        state = state.Withdraw(() => Balance -= number);
    }

    public void Freeze()
    {
        state = state.Freeze();
    }

    public void Close()
    {
        state = state.Close();
    }
}

It is simplistic and not production ready of course, but I'm not trying for it to be that. It is a simple example. This code actually shows well the problem I'm having.
Basically I have an IAccountState interface which represents the state / strategy. Now this could be considered a dependency and by allowing the Account class to KNOW how to manufacture the ActiveAccountState I enable the Account class to have more than 1 responsibilities. I could create an AccountStateFactory and make that a dependency on the account class. This would allow me to easily inject this newly created Factory dependency with the use of the Account class' constructor. But this way I, well, expose the implementation detail which is probably only interesting to the Account class and to none else. I guess that would make unit testing a tad bit easier.

My question would be how to know if something should be a dependency? Sometimes it is dead simple (ie. services, factories, providers etc.) but then there are times when I'm confused (like in this state / strategy example). Thanks in advance!

Best Answer

how to know if something should be a dependency?

Whenever you need something done but you don't want to do it here.

The big thing I'd like you to understand about reference passing (or Dependency Injection if you insist on being fancy) is that using a known good default is ok. You are not forbidden from using new. You are forbidden from using new without providing a way to override whatever that new makes you point at.

This is poorly understood in languages (like Java) that do not have named parameters. C# has them so you guys have no excuse. Josh Bloch gave Java users his builder pattern to fix this so if you know that, you also have no excuse.

Named parameters make it easy to have optional arguments. If you have that you can have default values easily. Your state should be an overridable default value. That lets you use DI without suffering with helpless classes that can't build themselves.

The philosophy behind this different approach to DI is called convention over configuration. Try it. I bet you'll find it makes these ideas much less theoretical and more useful.

There are other issues that you didn't ask about and since this isn't Code Review I won't get into them all, but I just can't ignore the double Balance one. Please tell me it doesn't represent dollars and cents. Double works well on discrete inches (base 2) and nondiscrete/continuous measurements (no base) but not on base 10 currencies. IEEE floating points and accountants rarely get along.