SOLID – Dependency Inversion Principle

This entry is part 1 of 1 in the series SOLID Principles
  • SOLID – Dependency Inversion Principle

Definition according to Wikipedia:

  1. High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).
  2. Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.

To understand these statements we should know about:

Abstractions and Concrete implementations

Abstract means a summary of the contents. In computer-programming abstractions hide internal details and only show functionality. We can create abstractions using interfaces or abstract classes.

On the other hand, a concrete implementation refers to a specific implementation of an abstraction.

Here, IRepository represents abstraction whereas DatabaseRepository is a concrete implementation of it.

High-Level Modules

High-Level modules are more general, in a software system, they might include business logic, application logic, user interface components, etc.

Low-Level Modules

Low-Level modules are more specific to implementation, they are designed to perform the functionality of the system.

To understand the Dependency Inversion Principle (DIP), consider a scenario in which a user registers for a system and the system sends an email to the user. In this example, we will assume that the system does not actually send the email, but rather just pretends to do so.

Suppose we have a class EmailService that sends emails and a class UserController that handles user registration. The UserController class needs to send an email to the user when they register, so it has a dependency on the EmailService class.

UserController: High-Level Modules

EmailService: Low-Level Modules

Without applying the dependency inversion principle, the UserController class looks like this:

Here, the UserController class is directly dependent on the EmailService class. If we want to change the way emails are sent (e.g. to use a different email service), we would have to modify the UserController class. This violates the dependency inversion principle, as the low-level EmailService class is depending on the high-level UserController class.

To follow the dependency inversion principle, we create an abstraction for the email service, such as IEmailService interface:

We then update the EmailService class to implement this interface:

Next, we update the UserController class to depend on the IEmailService interface rather than the EmailService class:

Now, the UserController class depends on the abstraction (the IEmailService interface) rather than the concrete implementation (the EmailService class).

This allows us to change the way emails are sent without modifying the UserController class. For example, we could create a new class SmtpEmailService that implements the IEmailService interface and use it instead of the EmailService class:

Leave a Reply

Your email address will not be published. Required fields are marked *