Принципы в C# - часть 6. Принцип инверсии зависимости.

  • Михаил
  • 12 мин. на прочтение
  • 105
  • 19 Dec 2018
  • 19 Dec 2018

Принцип инверсии зависимостей (сокращенно DIP) гласит:

Нужно полагаться на абстракции и их конкретную реализацию.

Преимущество инверсии зависимостей в том, что классам не нужно знать о конкретной реализации, а только о ее абстракции.
 

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

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

 

Приведенный выше код совершенно хорош, но он не соблюдает принцип инверсии зависимостей. Класс User знает о конкретной реализации UserFileRepository, что делает его слишком зависимым, если что-то нужно изменить в UserFileRepository, то UserServiceкласс нужно будет изменить.

Мы можем решить эту проблему, изменив конкретную ссылку на файл 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);
}

 

Теперь UserServiceон зависит не от конкретной реализации, UserDBRepositoryа от его контракта IUserRepository.
Если приложению необходимо перейти от сохранения к файлу и сохранить его в базу данных, мы можем просто создать другую конкретную реализацию IUserRepositoryи передать ее в качестве аргумента в 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);
}

 

В этом примере этот код можно изменить еще дальше, изменив, UserServiceчтобы иметь свой интерфейс и реализовать его.