Структура шаблона проектирования - Уровни (отрывок из книги)

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.

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

 Пример

     Сетевые протоколы, вероятнее всего, являются наиболее известным примером многоуровневой архитектуры. Подобные протоколы состоят из множества правил и конвенций, которые описывают, как компьютерные программы, находящиеся на разных машинах, обмениваются сообщениями между собой. Формат, содержание и значения всех сообщений определены. Все сценарии описаны детально, как привило, путем предоставления последовательностей действий (charts). Протокол определяет соглашения на множество абстрактных уровней, классифицируя, начиная с деталей передачи бит, и заканчивая высокоуровневой логикой приложения. Следовательно, проектировщики используют несколько второстепенных протоколов (subprotocols) и объединяют их в уровни. Каждый слой сотрудничает определенным образом с последующим нижележащим уровнем, а также использует его сервисы. Международная организация стандартизации (ISO) определила такую модель, как семиуровневую модель OSI (OSI 7 Layer Model).

Семиуровневая модель OSI

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

     В то время как OSI является важной эталонной моделью, TCP/IP, также известный как "Набор интернет протоколов" ("Internet protocol suite"), является общепринятым интернет протоколом. Мы воспользуемся TCP/IP для иллюстрации важной причины разбиения на уровни, а именно, повторное использование отдельных уровней в различных контекстах. Например, TCP может быть использован другими распределенными приложениями, такими как telnet и ftp.

 Контекст использования

     Большие системы, нуждающиеся в декомпозиции.

 Постановка задачи

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

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

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

     В таком случае необходимо искать компромиссы между следующими моментами:

  • Поздние изменения кода не должны расползаться по всей системе, то есть они должны быть ограничены одним компонентом и не затрагивать остальные. Интерфейсы должны быть стабильными, и даже могут быть устоявшимися стандартами.
  • Части системы должны быть заменяемыми. Компоненты должны иметь возможность заменяться различными альтернативными реализациями без затрагивания остальной части системы. Низкоуровневая платформа может предоставляться, но может быть предметом изменений в будущем. В то время как, фундаментальные изменения обычно требуют изменения кода и перекомпиляции системы, изменение конфигурации может быть произведено во время выполнения, путем использования управляющего интерфейса. Настраиваемый кэш или размер буфера, являются типичными примерами подобных изменений. Особой формой взаимозаменяемости может быть клиентский компонент, динамически переключающийся на различные реализации сервисов, которые изначально недоступны при запуске. Проектирование изменений, в общем, является главным помощником в элегантной эволюции системы.
  • В дальнейшем, может понадобиться разработать систему с похожими низкоуровневыми проблемами (issues), как в только что разработанной системе.
  • Похожие обязанности должны быть сгруппированы так, чтобы облегчить понимание, и предоставить максимальное удобство обслуживания. Каждый компонент должен быть связным, если какой-либо компонент реализует различное поведение, его целостность может быть нарушена. Группировка и связность являются несовместимыми.
  • Не существует "стандартного" разбиения компонент на модули.
  • Комплексные компоненты нуждаются в дальнейшей декомпозиции.
  • Пересечение границы между компонентами может быть связанно с потерей производительности, например, когда солидный объем данных должен быть передан через несколько границ, или когда существует много границ для пересечения.
  • Как правило, система разрабатывается командой программистов, поэтому работа должна быть ясно разделена в соответствии с ясными границами – это требование, которое зачастую рассматривается на стадии проектирования архитектуры.

 Решение задачи

     С высокоуровневой точкой зрения проект должен быть максимально прост. Необходимо структурировать систему на подходящее число уровней, и затем расположить их друг над другом. Начните с самого нижнего уровня абстракции, и назовите его Уровень 1. Это основа Вашей системы. Двигайтесь вверх по лестнице абстракций, располагая Уровень J над Уровнем J-1 до тех пор, пока не достигнете абстракции верхнего уровня – назовите ее Уровень N.

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

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