Unraveling SOLID: An introduction to the principles with Dart - Part 5: The Dependency Inversion Principle
Welcome to the final episode of our series on the SOLID principles. I'm thrilled about the progress we've made so far, and I hope each article has helped you better understand and apply these principles in your daily coding. Let's dive into our last topic.
D: Dependency Inversion Principle (DIP)
To grasp the Dependency Inversion Principle, let's first examine its defining phrase: "Depend on abstractions, not on concrete implementations." What does this mean? Essentially, it advocates for the decoupling of software modules. Instead of high-level modules relying on low-level modules, both should depend on abstractions. Let's clarify with an example.
Consider the following scenario:
In this example, we have two concrete classes, MechanicalKeyboard and LcdMonitor. The Computer class depends on both of these concrete classes, instantiated in its constructor. While this code may work fine, it suffers from a problem: high-level modules depending on low-level ones, leading to tight coupling and making testing difficult.
To address this, let's apply the Dependency Inversion Principle. Here's the refactored code:
In this refactored code, we've introduced abstract classes Keyboard and Monitor. The concrete classes MechanicalKeyboard and LcdMonitor now implement these abstract classes. Additionally, we've added a new class LedMonitor as another implementation of the Monitor abstraction. Now, the Computer class accepts variables of type Keyboard and Monitor, no longer depending on concrete implementations but on abstractions.
Just to make it clear look at the main function:
With this approach, our code is now decoupled, allowing for easier testing and flexibility in changing implementations without impacting the high-level modules.