Dependency inversion makes high-level classes depend on abstractions rather than concrete low-level implementations. Calling code or dependency injection chooses the implementation. section 6.2.5 section 7.1
Apply the principle by:
- Replacing a direct dependency, such as System.Random or DateTime.UtcNow, with an interface. section 6.2.5 section 7.1
- Accepting the abstraction through a constructor or resolving it through dependency injection. section 7.1
- Substituting deterministic implementations, mocks, or fakes during tests. section 7.0 section 7.1
Controlling time in a stopwatch
A stopwatch that reads DateTime.UtcNow directly requires Thread.Sleep and can produce slow or flaky tests. BasicStopwatch instead receives ISystemClock; production uses SystemClock, while tests provide exact timestamps and advance them directly. The same design resets and verifies elapsed time without waiting. section 7.1
Figure 6.3 A class diagram of DeckOfCards with a dependency on an interface to perform randomization along with implementations of that interface
Compare a DeckOfCards class coupled to System.Random with one coupled to a randomization interface and replaceable implementations. section 6.2.5





