DEV Community

loading...

Dependency Inversion Principle

Eduardo Julião
Software Developer | Geek since 1993 | @monsieurxuxu on twitter
・2 min read

Dependency Inversion Principle (DIP for short) states:

One should depend upon abstractions and their concrete implementation.

The advantage of Dependency Inversion is that the classes do not need to know about the concrete implementation, just its abstraction.

public class UserFileRepository
{
    void SaveUser(User user);
}

public class UserService
{
    public void CreateUser(User user)
    {
        UserFileRepository repository = new UserFileRepository();
        repository.SaveUser(user);
    }
}
Enter fullscreen mode Exit fullscreen mode

The code above is totally fine, but it does not respect the Dependency Inversion Principle. The User class know about the concrete implementation of the UserFileRepository, making it too dependent, if anything needs to be changed in UserFileRepository, the UserService class will need to be changed.

We can solve this issue by changing the concrete reference to an interface.

public interface IUserRepository
{
    void SaveUser(User user);
}

public class UserFileRepository : IUserRepository
{
    public void SaveUser(User user)
    {
        // Saves User to a file
    }
}

public class UserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public void CreateUser(User user)
    {
        _userRepository.SaveUser(user);
    }
}

void Main()
{
    IUserRepository repository = new UserFileRepository();
    UserService userService = new UserService(repository);
    User newUser = new User();
    userService.CreateUser(newUser);
}
Enter fullscreen mode Exit fullscreen mode

Now the UserService is not dependent on the concrete implementation of UserDBRepository but on its contract IUserRepository.
If the application needs to change from saving to a file and save it to a database, we can simply create another concrete implementation of the IUserRepository and pass it as an argument to the UserService.

public interface IUserRepository
{
    void SaveUser(User user);
}

public class UserFileRepository : IUserRepository
{
    public void SaveUser(User user)
    {
        // Saves User to a file
    }
}

public class UserDBRepository : IUserRepository
{
    public void SaveUser(User user)
    {
        // Saves User to a database
    }
}

public class UserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public void CreateUser(User user)
    {
        _userRepository.SaveUser(user);
    }
}

void Main()
{
    // Changed from File to DB repository
    IUserRepository repository = new UserDBRepository();
    UserService userService = new UserService(repository);
    User newUser = new User();
    userService.CreateUser(newUser);
}
Enter fullscreen mode Exit fullscreen mode

In this example, this code can be changed even further, changing the UserService to have its interface and implement it.

Discussion (0)