What is a Dependency
A dependency is an object a class needs to do its job. When a class creates its own dependencies with new, it's wired to them for good, and hard to test.
Apprentice · C# · OOP · Updated
After this lesson you can
- Identify a class's dependencies, and explain the problems of creating them inside the class
Key takeaways
- A dependency is an object a class needs to do its job, such as the
ClockthatGreeterneeds. - A class that creates its own dependencies with
newis hard-wired to them: to change one, you have to change the class itself. - A
Greeterthat makes its ownnew Clock()can't be tested reliably, because its greeting depends on when the test runs. - Dependency injection hands a class its dependencies from outside, so whoever creates the class decides which ones it gets.
Classes rarely work alone. A ProductDao needs a connection string. A controller needs a DAO. An order needs its menu items. When a class needs another object to do its job, that object is a dependency: the class depends on it.
A greeter that depends on a clock
Here's a Greeter that says good morning or good afternoon, depending on the time. It gets the time from a Clock:
Greeter greeter = new Greeter();
Console.WriteLine(greeter.Greet("Ada"));
public class Clock
{
public virtual int Hour => DateTime.Now.Hour;
}
public class Greeter
{
private readonly Clock clock = new Clock();
public string Greet(string name)
{
return clock.Hour < 12 ? quot;Good morning, {name}!" : quot;Good afternoon, {name}!";
}
}
Clock is a dependency of Greeter. And Greeter creates its own: new Clock(), right there in the class.
The trouble with new inside a class
It works. But run it in the morning and it says Good morning; run it after lunch and it says Good afternoon. Now try to test it:
- A test that expects Good morning, Ada! passes before noon and fails after. A test whose result depends on when you run it can't be trusted.
- To test the afternoon greeting, you'd have to wait until the afternoon.
- There's no way to hand
Greetera different clock, because it builds its own.
The same trouble shows up everywhere a class creates what it needs:
| The class creates | So it's stuck with | And testing it means |
|---|---|---|
new Clock() |
The real time | Waiting for the right time of day |
new ProductDao("Server=localhost;Database=Northwind;...") |
That database, on that server | Having that database, with the right rows in it |
new EmailSender() |
Sending real email | Sending real email to someone, every test run |
A class that creates its dependencies is hard-wired to them: to change one, you have to change the class itself.
The fix, in one sentence
Don't let the class create its dependencies. Hand them in from outside, so whoever creates the class decides which clock, which database, which email sender it gets. That's dependency injection, and the next lesson shows how.
Check yourself
1 question to try on the lesson page.
So what
Every new inside a class for something it depends on is a decision made too early. Spot those, and you've found the places where your code is hard to test and hard to change.