Âåðíóòüñÿ â áèáëèîòåêó

Структура и поведение многоуровневых приложений (отрывок из книги)  

Èñòî÷íèê:  Buschmann F., Meunier R., Rohnert H., Sommerlad P., Stal M., Sommerlad P. Pattern-Oriented Software Architecture, Volume 1: A System of Patterns. - US: John Wiley, 1996. - 634 p.

  Àâòîðû: Douglas Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann. Перевод: Гордеев А.Г.

Структура

Каждый уровень может быть описан следующей CRC карточкой:

Главной структурной характеристикой шаблона "Уровни", является то, что сервисы Уровня J используются только Уровнем J+1 – и больше нет никаких дальнейших прямых зависимостей. Эту структуру можно сравнить со стеком, или даже с луком. Каждый отдельный уровень защищает все нижние уровни от непосредственного доступа со стороны верхних уровней.

 

 

Рассматривая отдельные уровни более детально, можно обнаружить, что это множество сущностей, состоящее из различных компонентов. На следующем рисунке, каждый уровень содержит три компоненты. В среднем уровне есть две взаимодействующие компоненты. Компоненты из различных уровней вызывают друг друга непосредственно – в другой архитектуре каждый уровень защищен внутренним унифицированным интерфейсом. При таком проектировании, Компонент 2.1 больше не вызывает Компонент 1.1 непосредственно, а вызывает интерфейсный объект Уровня 1, который делегирует запрос необходимой компоненте. В разделе "Реализация" мы обсудим преимущества и недостатки непосредственных вызовов.

 

 

Динамика

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

Сценарий 1 наиболее известный. Модули клиентов посылают запросы уровню N (Layer N). Если Уровень N не может обработать поступивший запрос, он делегирует его слою N-1 и так далее, пока запрос не достигнет Уровня 1. Если необходим ответ на запрос, он возвращается от Уровня 1 к Уровню N.

Сценарий 2 отражает коммуникацию между уровнями, которая начинается от Уровня 1, например, когда  устройство обнаруживает входные данные. Драйвер преобразует входной запрос к внутреннему формату и пересылается на Уровень 2, который начинает интерпретирование запроса, и так далее. При таком подходе данные продвигаются с нижнего уровня на верхний уровень. Нисходящее движение данных часто называется – “запрос”, а вверх идущее – “сообщение”. Указанный в Сценарии 1 запрос часто распадается на несколько запросов к нижележащему уровню. Соответственно, несколько низкоуровневых сообщений могут группироваться в одну более высокоорганизованную структуру, либо остаться в соотношении один к одному.

Сценарий 3 описывает ситуацию, когда запрос следует только через подмножество уровней. Запрос верхнего уровня может только попасть на нижележащий уровень N-1, если этот уровень может обработать запрос в полном объеме. Например, когда уровень N-1 представляет собой кэш, и запрос от уровня N может быть удовлетворен без пересылки его на Уровень 1. Необходимо отметить, что подобные кэширующие уровни сохраняют информацию о состоянии, в то время как уровни, которые только делегирую запросы как правило, не хранят состояния. Уровни, не хранящие состояние, имеют более простую реализацию и поощряют реентерабельность.

Сценарий 4 описывает ситуацию схожую со Сценарием 3. Событие обнаруженное на Уровне 1, останавливается на Уровне 3, вместо того чтоб продолжить продвижение на Уровень N. Например, запрос на повторное получение данных может поступить от клиента до того как был получен ответ на предыдущий, который не так давно был послан. Тем временем сервер уже отправил ответ, и ответ и новый запрос пересекаются на Уровне 3. В этом случае Уровень 3 с серверной стороны может распознать эту ситуацию, и снова отправить запрос без дальнейших действий.

Сценарий 5 включает два стека по N уровней каждый. Этот сценарий известен по протоколу взаимодействия, где стек известен как ‘стек проколов’. Уровень N левого стека посылает запрос. Запрос движется вниз через нижележащие уровни, пока не достигнет Уровня 1, который пересылает его Уровню 1 правого стека, и далее продвигается к верхнему Уровню N. Ответ на запрос движется в обратном направлении.