Skip to content

Dependency Inversion Principle [DIP]

High level modules (e.g. business logic) should not depends on low level modules (e.g. infrastructure). Both should depend on ABSTRACTIONS

DETAILS should depend on ABSTRACTIONS.
ABSTRACTIONS should not depend on DETAILS.

Dependencies

references required to compile or run (e.g. reflection)

Abstractions

Describe 'what needs to be done' (but not how)

  • interfaces
  • abstract base classes
  • types that cannot be instantiated (broadly speaking)

Details

Describe the 'how' of what needs to be done

Can also include:

  • details as parameters
  • details as return types

Examples of low level dependencies

  • databases
  • files system
  • email
  • configuration
  • Web APIs
  • system clock

Hidden Direct Dependencies

static calls and new keyword, could indicate a direct dependency. These can create tight coupling which can make it difficult to isolate and unit test and can cause duplicated code.

Using new - 'new is glue'

  • it creates coupling
  • do you need to specify an implementation?
  • could you use an abstraction instead?

Explicit Dependency Principle

Your classes shouldn't have hidden dependencies in them. List your classes dependencies upfront, in the constructor. Think of them like the ingredients in a recipe - it's best if you know exactly what you need, before you start!

Dependency Injection [DI]

You don't create your own dependencies, it's the client's job to inject them into your class. (and naturally your class should declare its dependencies as abstractions)

Dependencies can be injected as:-

  • constructor arguments (preferred method)
  • properties
  • method arguments

By using constructor arguments it's possible to leverage IOC (Inversion of Control) containers to construct types and their dependencies.

See also the Strategy Design Pattern