Dependency Inversion Principle (DIP) is one of the principles of object-oriented design, which is the "D" in the SOLID principle. The core idea of the Dependency Inversion Principle is that high-level strategic business rules should not depend on low-level concrete implementation details, but both should depend on the abstraction.
The principle of inversion of reliance contains two main basic points:
-
Abstraction should not depend on details: The abstraction layer in a system (high-level modules) should not depend on the concrete implementation (low-level modules), but rather both should depend on the abstraction (e.g., interfaces or abstract classes).
-
Details should rely on abstraction: Concrete implementations should depend on the abstraction so that concrete implementations can be replaced or modified without modifying the abstraction layer code.
The advantages of relying on the principle of inversion include:
- Reduced coupling: Since inter-module dependencies are based on abstraction, direct dependencies between modules are reduced and coupling is lowered.
- Improve modularity: The system is more easily decomposed into reusable modules because the interaction between the modules takes place through abstract interfaces.
- Enhanced flexibility: Replacing or upgrading a part of the system becomes easier because the specific implementation can be changed independently of the high-level policy.
In practice, the principle of dependency inversion can be realized in the following ways:
- Use interfaces or abstract classes to define contracts between system components.
- Specific implementations are injected into objects that need them via Dependency Injection (DI), rather than allowing the objects to create or look up these implementations themselves.
- Avoid using concrete classes directly in high-level modules, instead referencing them via abstraction.
The principle of dependency inversion is the basis for the realization of the Open/Closed Principle, which states that software entities should be open to extensions and closed to modifications. With dependency inversion, we can more easily extend the functionality of the system without modifying the existing code.
Here's a look at a simple Java code example to give us a better understanding of the application of the principle of dependency inversion:
First, we define an abstract interface that represents a system that can send messages:
public interface MessageService {
void sendMessage(String message);
}
Then, we create a specific sending service to implement this interface:
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
("Sending email: " + message);
}
}
Next, we have a high-level strategy class that uses theMessageService
interface rather than a specificEmailService
Class:
public class NotificationService {
private MessageService messageService;
// Constructor Injection Dependencies
public NotificationService(MessageService messageService) {
= messageService;
}
public void notifyUser(String message) {
// Dependent on abstraction,Rather than a concrete realization
(message);
}
}
Finally, we can use this system in our client code:
public class Client {
public static void main(String[] args) {
// Creating a specific messaging service
MessageService emailService = new EmailService();
// Injecting specific messaging services into high-level policies
NotificationService notificationService = new NotificationService(emailService);
// Sending messages using high-level policies
("Hello, this is a test email.");
}
}
In this example, theNotificationService
class is a high-level policy class that relies on theMessageService
interface abstraction. We inject the concrete messaging service through the constructorEmailService
. This way, if in the future we need to change the implementation of the messaging service (e.g., using theSmsService
), we just need to create a new implementation class and inject it into theNotificationService
without modifying theNotificationService
of the code. This embodies the spirit of the principle of dependency inversion.