Оставив эти возможности открытыми, позже мы сможем изменить способ развертывания системы, исходя из особенностей ее развития.
Поток управления на рис. 33.2 движется справа налево. Входные данные поступают в контроллеры и затем обрабатываются интеракторами. Презентаторы форматируют результаты обработки и передают их представлениям для отображения.
Обратите внимание, что не все стрелки направлены справа налево. Фактически большинство из них направлено слева направо. Это объясняется тем, что архитектура следует правилу зависимости . Все зависимости пересекают архитектурные границы в одном направлении и всегда направлены в сторону компонентов, содержащих политики более высокого уровня.
Также отметьте, что отношения использования (открытые стрелки) совпадают с направлением потока управления, а отношения наследования (закрытые стрелки) направлены против потока управления. Это отражает использование принципа открытости/закрытости, который требует, чтобы зависимости были направлены в правильном направлении и изменения в низкоуровневых деталях не затрагивали высокоуровневые политики.
Диаграмма архитектуры на рис. 33.2 включает разделение по двум измерениям. Первое — разделение на основе действующих лиц согласно принципу единственной ответственности; второе соответствует правилу зависимости. Цель обоих — разделить компоненты, изменяющиеся по разным причинам и с разной скоростью. Причины в данном случае соответствуют действующим лицам, а скорости — разным уровням политик.
После структуризации кода таким способом появляется возможность смешивать и распределять его по единицам развертывания как угодно. Вы сможете группировать компоненты в любые единицы развертывания, имеющие смысл, и менять правила группировки с изменением условий.
Глава 34. Недостающая глава
Автор: Симон Браун (Simon Brown), 2 марта 2017
Все советы, которые вы прочитали к настоящему моменту, безусловно, помогут вам проектировать замечательные приложения, состоящие из классов и компонентов с четко определенными границами, понятными обязанностями и управляемыми зависимостями. Но как всегда, дьявол кроется в деталях реализации, и действительно, очень легко споткнуться о последнее препятствие, если не уделить ему должного внимания.
Представим, что мы строим книжный онлайн-магазин и один из вариантов использования, который нам предлагается внедрить, — возможность просмотра клиентами состояния своих заказов. Пример, следующий ниже, описывается с позиции языка Java, однако принципы в равной степени применимы к другим языкам программирования. Отложим пока чистую архитектуру в сторону и рассмотрим несколько подходов к проектированию и организации кода.
Первый и самый простой, пожалуй, подход — организация традиционной многоуровневой архитектуры, в которой код разделяется по функциональному признаку. Этот подход часто называют «упаковкой по уровням». На рис. 34.1 показано, как могла бы выглядеть соответствующая UML-диаграмма классов.
Рис. 34.1.Упаковка по уровням
В такой типичной многоуровневой архитектуре один уровень выделяется для веб-кода, один уровень — для «бизнес-логики» и один уровень — для работы с хранилищем данных. Иными словами, горизонтальные уровни используются как способ группировки по подобию. В «строгой многоуровневой архитектуре» уровни должны зависеть только от следующего смежного уровня. В Java уровни обычно реализуются в виде пакетов. Как показано на рис. 34.1, все зависимости между уровнями (пакетами) направлены вниз. В этом примере у нас имеются следующие Java-типы:
• OrdersController: веб-контроллер, иногда что-то вроде MVC-контроллера из Spring, обрабатывающего запросы из Веб.
• OrdersService: интерфейс, определяющий «бизнес-логику», связанную с заказами.
• OrdersServiceImpl: реализация службы заказов [63] Это ужасное имя для класса, но, как будет показано ниже, в действительности это не имеет большого значения.
.
• OrdersRepository: интерфейс, определяющий порядок доступа к информации о заказах в хранилище.
Читать дальше
Конец ознакомительного отрывка
Купить книгу