Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций?

В последние пару дней я много читал о внедрении зависимости / инверсии управления / инверсии зависимости. Я думаю, что теперь мое понимание концепции намного лучше. Но я все еще не получаю следующее из Википедии:

A. Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. Б. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Я понимаю, что часть модулей высокого уровня не должна зависеть от модулей низкого уровня. Но меня смущают абстракции и детали. Может кто-нибудь, пожалуйста, упростите их для меня. Благодарю.

4 ответа

Решение

Это означает, что если детали меняются, они не должны влиять на абстракцию. Абстракция - это способ, которым клиенты видят объект. То, что происходит внутри объекта, не имеет значения. Возьмем, к примеру, автомобиль, педали, рулевое колесо и рычаг переключения передач являются абстракцией того, что происходит внутри двигателя. Они не зависят от деталей, потому что, если кто-то поменяет мой старый двигатель на новый, я все равно смогу вести машину, не зная, что двигатель изменился.

Детали, с другой стороны, ДОЛЖНЫ соответствовать тому, что говорит абстракция. Я не хотел бы реализовать двигатель, который внезапно заставляет тормоза удваивать скорость автомобиля. Я могу повторно установить тормоза любым способом, каким хочу, если внешне они ведут себя одинаково.

Интересный случай, когда абстракция зависит от деталей, - это когда вы определяете интерфейс, который наследуется от IDisposable. Взгляните на следующую абстракцию:

public interface ICustomerRepository : IDisposable
{
    Customer GetById(Guid id);
    Customer[] GetAll();
}

Примечание: IDisposable интерфейс, специфичный для.NET, но вы можете легко представить, что ваш интерфейс содержитDisposeсам метод вместо наследования от такого интерфейса.

Это может выглядеть удобно для ICustomerRepository реализовать IDisposable, Таким образом, любой вызывающий объект может распоряжаться репозиторием, и таким образом реализация может распоряжаться соединением или единицей работы, которые оно использует внутри.

Интерфейс, однако, теперь написан с определенной реализацией, поскольку совсем не очевидно, что все ICustomerRepository реализации должны будут очистить любые ресурсы. Интерфейс поэтому пропускает детали реализации и поэтому нарушает принцип инверсии зависимости.

Подумайте о работе, которую вам нужно выполнить, и о том, как далеко она находится от того места, где вы сейчас пишете код. Там есть спектр; ваша позиция на нем представляет объем работы, которую вам нужно сделать, чтобы задействовать эту функциональность.

Абстракции перемещают эту позицию ближе к коду, который вы пишете. Например, если вам нужно вызвать веб-сервис, вы можете либо: 1) написать вызывающий код непосредственно там, где вам нужно его использовать, либо 2) поместить эти детали за абстракцией (такой как интерфейс).

В этом случае № 1 приближает вас к веб-службе в спектре, а № 2 - ближе к вашей работе. Можно сказать, что абстракция является мерой того, как далеко вы должны растянуть свой разум, чтобы понять работу, которую вам нужно сделать.

Это означает, что каждый кусок работы можно абстрагировать, чтобы он был "ближе" к коду, использующему его. Поскольку обе стороны операции зависят от абстракций, они оба становятся более понятными, и ни одна из сторон не должна утаивать знание разрыва между ними - в этом и заключается работа абстракции.

Вау, это было абстрактно.

Пример абстракции и детали: поток предоставляет интерфейс для чтения токена. Это абстракция.

Потоковая реализация потока обязана реализовывать интерфейс, определенный абстракцией: поэтому он зависит от него. Если он предоставляет другой интерфейс (по одному для чтения 100 символов за раз), он не может претендовать на реализацию той же абстракции.

Другие вопросы по тегам