Dependency Inversion Principle
The Dependency Inversion Principle is a design principle that states that high-level modules should not depend on low-level modules, but rather both should depend on abstractions. This means that the design of a system should depend on abstractions, rather than on concrete implementations.
To follow the Dependency Inversion Principle in your design:
- Identify the high-level and low-level modules in your system. The high-level modules are typically the ones that provide the overall functionality of the system, while the low-level modules are the ones that provide the specific implementation details.
- Create abstractions for low-level modules.
- Have high-level modules depend on abstractions.
- Have low-level modules implement abstractions.
Here's an example that violates the Dependency Inversion Principle in Python:
This example violates the Dependency Inversion Principle because the BackupService
class has a direct dependency on the FileSystem
class. This means that any changes to the FileSystem
class could potentially affect the BackupService
class, and vice versa. This violates the principle, as it means that the high-level BackupService
class depends on the low-level FileSystem
class.
To fix this issue and follow the Dependency Inversion Principle, we can introduce an abstraction for the file system functionality. Here's the refactored implementation:
In this revised version of the system, the BackupService
class depends on the IFileSystem
interface rather than on the FileSystem
class directly. This follows the Dependency Inversion Principle, as it ensures that the high-level BackupService
class does not depend on the low-level FileSystem
class.
By introducing the abstraction, we have decoupled the BackupService
class from the FileSystem
class, making the system more flexible and easier to modify. If we need to change the way that the system reads and writes files, we can do so by modifying the FileSystem
class without affecting the BackupService
class. This allows us to add new features or make changes to the system without causing unintended consequences.
However, this example still uses an object of the FileSystem
class. Is this not a violation of the Dependency Inversion Principle?
No, using an object of the FileSystem
class in the BackupService
class does not necessarily violate the Dependency Inversion Principle. The key principle here is that the high-level module (in this case, the BackupService
class) should depend on abstractions, rather than on concrete implementations.
In this example, the BackupService
class is still using an object of the FileSystem
class. However, the BackupService
class is not directly depending on the FileSystem
class. Instead, it is depending on the IFileSystem
interface, which is implemented by the FileSystem
class.
This means that the BackupService
class is not tightly coupled to the FileSystem
class. If we need to change the way that the system reads and writes files, we can do so by creating a new class that implements the IFileSystem
interface and using that class instead of the FileSystem
class. This allows us to make changes to the low-level FileSystem
class without affecting the high-level BackupService
class.