Должны ли мы использовать интерфейс в качестве зависимости (в ctor), даже если мы ожидаем, что это одна конкретная c реализация? - PullRequest
1 голос
/ 14 марта 2020

Допустим, у нас есть класс, например SqlIdProvider, для которого требуется репозиторий SQL для выполнения некоторых операций. У нас также есть класс SqlRepository, который реализует интерфейс IRepository следующим образом:

public interface IRepository {
    // All repository methods here.
}

public sealed class SqlRepository : IRepository {
    // All repository methods here.
}

public sealed class SqlIdProvider {
    private IRepository _repository;

    public SqlIdProvider(IRepository repository){
        _repository = repository;
    }
}

* SqlIdProvider сильно зависит от SqlRepository, поэтому он не будет работать, если я предоставлю Например, экземпляр следующего класса:

public sealed class MongoRepository : IRepository {
    // All repository methods here.
}

Однако подпись SqlIdProvider говорит мне, что я мог бы просто предоставить один из них, и все должно быть в порядке.

В этом В этой ситуации я обычно думаю о трех вариантах:

1) Сохраняйте как есть и надеюсь, что имени будет достаточно, чтобы другие знали, что вы не должны предоставлять MongoRepository для SqlIdProvider (хотя не применяя его каким-либо образом).

2) Измените конструктор SqlIdProvider, чтобы взять бетон SqlRepository. Это привело бы к выполнению требования, но это затруднило бы модульное тестирование, заставив нас удалить ключевое слово sealed из SqlRepository, чтобы иметь возможность подделать реализацию (кстати, мне нравится, что классы должны быть запечатаны, если нет веской причины не делать этого) .

3) Создайте пустой интерфейс, расширяющий IRepository, предназначенный для единственной цели SQL хранилищ, называемый ISqlRepository. Теперь мы могли бы изменить конструктор SqlIdProvider, чтобы вместо него использовать интерфейс ISqlRepository.

public interface ISqlRepository : IRepository {
    // This one is empty on purpose.
}

Мне кажется, вариант 3) кажется наиболее привлекательным, но все равно кажется, что я делаю что-то не так с созданием пустого интерфейса.

Есть ли лучший способ, которым мы можем быть явными с ограничением и в то же время позволить простое модульное тестирование?

...