User Tools

Site Tools


principles:dependency_inversion_principle

Dependency Inversion Principle (DIP)

Variants and Alternative Names

Context

Principle Statement

Depend on abstractions.1)

Description

A simplified description of DIP is that a variable declaration should always have the (static) type of an abstract class or interface. By doing so a module depends only on this abstraction. The concrete subclass realizing the details is referenced only once, namely when it is instantiated.

The more elaborate definition by Robert C. Martin reads as follows:

a. High-level modules should not depend on low-level modules. Both should depend on abstractions.
b. Abstractions should not depend on details. Details should depend on abstractions.2)

Following this rule leads to “inverted” dependencies compared to classical procedural approaches. The following diagram shows the classical approach. A high-level module A uses a low-level module B.

When applying DIP, both modules depend on the abstraction (note that in UML diagrams all arrows point into the direction of the dependency):

B is not depended upon anymore but it depends on another module. This is the inverted dependency.

Rationale

When DIP is not applied, only the low-level modules can be reused independently. The higher-level modules depend on the others, so trying to reuse them makes it necessary to either also reuse the lower-level modules or to change the higher-level module. The former is often not wanted because reuse is often done in another context where the lower-level modules do not fit. And the latter is error-prone and requires additional work as it requires changes to already working modules.

Strategies

  • Apply the Dependency Inversion Pattern
  • Use events, the observer pattern, etc. to remove dependencies
  • Apply other forms of dependency inversion
  • Have an interface type for every class
  • Declare only interface types so that an object variable generally has an interface as static type and a concrete class as dynamic type
  • Do not derive classes from concrete ones (i.\,e.\ non-abstract classes)
  • Do not override already implemented methods in subclasses

Caveats

It is normally not helpful to apply DIP to value objects.

Furthermore note that applying dependency inversion pattern (see strategies) introduces an abstraction. FIXME explain Super-A vs. ReqByB

See section contrary principles.

Origin

Evidence

Accepted: DIP is part of the well-known SOLID principle collection.

Relations to Other Principles

Generalizations

  • Low Coupling (LC): LC aims at reducing the dependencies to other modules. One way to do so is to only depend on abstractions. DIP is about this aspect.
  • Dependency Abstraction (DA) 3): While DIP is about inverting dependencies going from lower to higher architecture layers, DA also works on the same layer where an “inversion” is not helpful.

Specializations

Contrary Principles

  • More Is More Complex (MIMC): DIP demands introducing abstractions, especially abstract classes or interfaces.

Complementary Principles

  • Model Principle (MP): DIP demands having abstractions. MP tells how these abstractions can look like.

Principle Collections

OOD Principle Language
General Principles
ML KISS MIMC DRY GP RoE
Modularization Principles
MP HC ECV
Module Communication Principles
TdA/IE LC DIP
Interface Design Principles
EUHM PLS UP
Internal Module Design Principles
IH/E IAP LSP PSU

Examples

Example 1: Furnace

An example for a high-level module is a regulator module of a furnace. The classical approach would result in the regulator depending on a thermometer and a heater. in such a case it would not be possible to reuse the regulator module for regulating the fluid level of a reservoir or the speed of a car. A DIP-compliant solution would result in the regulator just depending on a sensor module and an actuator module and thermometer and header implementing these interfaces. By doing so thermometer, heater, and regulator can be reused independently.

This example is taken from 4) and slightly modified.

Example 2: Client Repository

Let's say the high-level module (your business logic), wants to be able to add or remove users to the database. Instead of it talking to the database directly, it defines an interface called ClientRepository which contains the methods the business logic needs. Then a MySQLClientRepository concretion, implements that interface and uses a database library to submit the queries. Since the interface is decided by the business logic, the high-level policy is protected from changes in the database library. More over, since the interface was defined by the business logic, it does not reveal anything about the underlying implementation, which allows different types of user repositories, such as a WebserviceClientRepository implementation (OCP). Finally the MySQLClientRepository and business logic can be built as well as deployed independently.

Description Status

Further Reading

Discussion

Discuss this wiki article and the principle on the corresponding talk page.

principles/dependency_inversion_principle.txt · Last modified: 2021-10-18 21:23 by christian