Чтение онлайн

на главную - закладки

Жанры

Чистая архитектура. Искусство разработки программного обеспечения
Шрифт:

Во всех этих и многих других ситуациях применим принцип LSP, потому что существуют пользователи, зависящие от четкого определения интерфейсов и замещаемости их реализаций.

Лучший способ понять значение LSP с архитектурной точки зрения – посмотреть, что случится с архитектурой системы при нарушении принципа.

Пример нарушения LSP

Допустим, что мы взялись за создание приложения, объединяющего несколько служб, предоставляющих услуги такси. Клиенты, как предполагается, будут использовать наш веб-сайт для поиска подходящего такси, независимо от принадлежности к той или иной компании. Как только клиент подтверждает заказ, наша система передает его выбранному

такси, используя REST-службу.

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

Допустим, что для водителя с именем Bob адрес URI отправки заказа выглядит так:

purplecab.com/driver/Bob

Наша система добавит в конец этого URI информацию о заказе и пошлет его методом PUT:

purplecab.com/driver/Bob

/pickupAddress/24 Maple St.

/pickupTime/153

/destination/ORD

Это явно означает, что все службы должны соответствовать общему интерфейсу REST. Они должны единообразно интерпретировать поля

pickupAddress
,
pickupTime
и
destination
.

Теперь предположим, что компания такси Acme наняла несколько программистов, которые ознакомились со спецификацией недостаточно внимательно. Они сократили имя поля

destination
до
dest
. Компания Acme – крупнейшая компания такси в нашем регионе, и бывшая жена президента компании Acme вышла замуж за президента нашей компании, и… В общем, вы поняли. Что может произойти с архитектурой нашей системы?

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

Решить поставленную задачу проще всего простым добавлением инструкции if в модуль, занимающийся пересылкой заказов:

if (driver.getDispatchUri. startsWith("acme.com"))…

Конечно, ни один архитектор, дорожащий своей репутацией, не позволил бы добавить такую конструкцию в систему. Появление слова «acme» непосредственно в коде создает возможность появления самых разных неприятностей, не говоря уже о бреши в безопасности.

Например, представьте, что компания Acme добилась большого успеха, купила компанию Purple Taxi и объединенная компания решила сменить имя и адрес веб-сайта и объединить все системы оригинальных компаний. Получается, что теперь мы должны добавить еще одну инструкцию if для «purple»?

Архитектор должен изолировать систему от ошибок, подобных этой, и добавить модуль, управляющий созданием команд доставки заказов в соответствии с параметрами, указанным для URI в базе данных с настройками. Настройки могли бы выглядеть как-то так:

UPI

Acme.com

Формат команды

/pickupAddress/%s/pickupTime/%s/dest/%s

UPI

*.*

Формат команды

/pickupAddress/%s/pickupTime/%s/destination/%s

В результате архитектор вынужден

добавить важный и сложный механизм из-за того, что интерфейсы не всех REST-служб оказались совместимыми.

Заключение

Принцип подстановки Барбары Лисков может и должен распространяться до уровня архитектуры. Простое нарушение совместимости может вызвать загрязнение архитектуры системы значительным количеством дополнительных механизмов.

10. Принцип разделения интерфейсов

Происхождение названия принципа разделения интерфейсов (Interface Segregation Principle; ISP) наглядно иллюстрирует схема на рис. 10.1.

Рис. 10.1. Принцип разделения интерфейсов

В данной ситуации имеется несколько классов, пользующихся операциями в классе

OPS
. Допустим, что
User1
использует только операцию
op1
,
User2
– только
op2
и
User3
– только
op3
.

Теперь представьте, что

OPS
– это класс, написанный на таком языке, как Java. Очевидно, что в такой ситуации исходный код
User1
непреднамеренно будет зависеть от
op2
и
op3
, даже при том, что он не пользуется ими. Эта зависимость означает, что изменения в исходном коде метода
op2
в классе
OPS
потребуют повторной компиляции и развертывания класса
User1
, несмотря на то что для него ничего не изменилось.

Эту проблему можно решить разделением операций по интерфейсам, как показано на рис. 10.2.

Рис. 10.2. Разделение операций

Если снова представить, что этот интерфейс реализован на языке со строгим контролем типов, таком как Java, исходный код

User1
будет зависеть от
U1Ops
и
op1
, но не от
OPS
. То есть изменения в
OPS
, которые не касаются
User1
, не потребуют повторной компиляции и развертывания
User1
.

Принцип разделения интерфейсов и язык

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

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

Поделиться:
Популярные книги

Шериф

Астахов Евгений Евгеньевич
2. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
6.25
рейтинг книги
Шериф

Меч Предназначения

Сапковский Анджей
2. Ведьмак
Фантастика:
фэнтези
9.35
рейтинг книги
Меч Предназначения

Конь Рыжий

Москвитина Полина Дмитриевна
2. Сказания о людях тайги
Проза:
историческая проза
8.75
рейтинг книги
Конь Рыжий

Отверженный VIII: Шапка Мономаха

Опсокополос Алексис
8. Отверженный
Фантастика:
городское фэнтези
альтернативная история
аниме
5.00
рейтинг книги
Отверженный VIII: Шапка Мономаха

Имя нам Легион. Том 1

Дорничев Дмитрий
1. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 1

Хозяйка старой пасеки

Шнейдер Наталья
Фантастика:
попаданцы
фэнтези
7.50
рейтинг книги
Хозяйка старой пасеки

Кодекс Охотника. Книга VIII

Винокуров Юрий
8. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга VIII

Эволюционер из трущоб. Том 3

Панарин Антон
3. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
6.00
рейтинг книги
Эволюционер из трущоб. Том 3

Сын Тишайшего 3

Яманов Александр
3. Царь Федя
Фантастика:
попаданцы
альтернативная история
фэнтези
5.00
рейтинг книги
Сын Тишайшего 3

Потомок бога 3

Решетов Евгений Валерьевич
3. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Потомок бога 3

Сумеречный стрелок

Карелин Сергей Витальевич
1. Сумеречный стрелок
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сумеречный стрелок

Отверженный. Дилогия

Опсокополос Алексис
Отверженный
Фантастика:
фэнтези
7.51
рейтинг книги
Отверженный. Дилогия

Плохой парень, Купидон и я

Уильямс Хасти
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Плохой парень, Купидон и я

Архил...? Книга 2

Кожевников Павел
2. Архил...?
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Архил...? Книга 2