Mark As Completed Discussion

Dependency Inversion Principle (DIP)

The Dependency Inversion Principle (DIP) is one of the five object-oriented design principles that form SOLID. It emphasizes that high-level modules should not depend on low-level modules; both should depend on abstractions.

The DIP states that the inversion of control should be applied to achieve loose coupling and improved flexibility. Instead of high-level modules depending on low-level modules directly, they should both depend on abstractions, typically defined by interfaces or abstract classes.

To understand the need for the DIP, let's consider an example where we have a UserController class, which depends on a UserRepository class to retrieve user data from a database:

TEXT/X-JAVA
1public class UserController {
2    private UserRepository userRepository;
3
4    public UserController() {
5        this.userRepository = new UserRepository();
6    }
7
8    public void getUser(int userId) {
9        User user = userRepository.getUser(userId);
10        // process user data
11    }
12}
13
14public class UserRepository {
15    public User getUser(int userId) {
16        // retrieve user data from database
17        return user;
18    }
19}

In this example, the UserController directly depends on the UserRepository class, creating a strong coupling between the two. This makes the UserController less flexible and harder to test, as it becomes tightly coupled to the implementation details of the UserRepository.

By applying the DIP, we can achieve loose coupling and improved flexibility. Instead of the UserController depending directly on the UserRepository, we can introduce an abstraction, such as an IUserRepository interface, that both the UserController and UserRepository depend on:

TEXT/X-JAVA
1public interface IUserRepository {
2    User getUser(int userId);
3}
4
5public class UserController {
6    private IUserRepository userRepository;
7
8    public UserController(IUserRepository userRepository) {
9        this.userRepository = userRepository;
10    }
11
12    public void getUser(int userId) {
13        User user = userRepository.getUser(userId);
14        // process user data
15    }
16}
17
18public class UserRepository implements IUserRepository {
19    public User getUser(int userId) {
20        // retrieve user data from database
21        return user;
22    }
23}

In this refactored example, the UserController now depends on the IUserRepository interface instead of the UserRepository class directly. This allows for better separation of concerns and flexibility, as we can easily swap out different implementations of the IUserRepository interface without affecting the UserController.

By following the DIP, we can achieve loose coupling, inversion of dependencies, and improved flexibility in our codebase. This leads to code that is easier to understand, maintain, and test.

JAVA
OUTPUT
:001 > Cmd/Ctrl-Enter to run, Cmd/Ctrl-/ to comment