2005 г.
Обзор паттернов проектирования
Ольга Дубина
3.2 Паттерны проектирования поведения классов/обьектов
3.2.1 Интерпретатор (Interpreter ) - GoF
Проблема |
Имеется часто встречающаяся, подверженная изменениям задача. |
Решение |
Создать интерпретатор, который решает данную задачу. |
Пример |
Задача поиска строк по образцу может быть решена посредством создания интерпретатора, определяющего грамматику языка. "Клиент" строит предложение в виде абстрактного синтаксического дерева, в узлах которого находятся объекты классов "НетерминальноеВыражение" и "ТерминальноеВыражение" (рекурсивное), затем "Клиент" инициализирует контекст и вызывает операцию Разобрать(Контекст). На каждом узле типа "НетерминальноеВыражение" определяется операция Разобрать для каждого подвыражения. Для класса "ТерминальноеВыражение" операция Разобрать определяет базу рекурсии. "АбстрактноеВыражение" определяет абстрактную операцию Разобрать, общую для всех узлов в абстрактном синтаксическом дереве. "Контекст" содержит информацию, глобальную по отношению к интерпретатору.
|
Преимущества |
Грамматику становится легко расширять и изменять, реализации классов, описывающих узлы абстрактного синтаксического дерева похожи (легко кодируются). Можно легко изменять способ вычисления выражений. |
Недостатки |
Сопровождение грамматики с большим числом правил затруднительно. |
3.2.2 Итератор (Iterator) или Курсор (Cursor) - GoF
Проблема |
Составной объект, например, список, должен предоставлять доступ к своим элементам (объектам), не раскрывая их внутреннюю структуру, причем перебирать список требуется по-разному в зависимости от задачи. |
Решение |
Создается класс "Итератор", коорый определяет интерфейс для доступа и перебора элементов, "КонкретныйИтератор" реализует интерфейскласса "Итератор" и следит за текущей позицией при обходе "Агрегата". "Агрегат" определяет интерфейс для создания объекта - итератора. "КонкретныйАгрегат" реализует интерфейс создания итератора и возвращает экземпляр класса "КонкретныйИтератор", "КонкретныйИтератор" отслеживает текущий объект в агрегате и может вычислить следующий объект при переборе.
|
Преимущества |
Поддерживает различные способы перебора агрегата, одновременно могут быть активны несколько переборов. |
3.2.3 Команда (Command), Действие (Action) или Транзакция (Транзакция) - GoF
Проблема |
Необходимо послать объекту запрос, не зная о том, выполнение какой операции запрошено и кто будет получателем. |
Решение |
Инкапсулировать запрос как объект. "Клиент" создает объект "КонкретнаяКоманда", который вызывает операции получателя для выполнения запроса, "Инициатор" отправляет запрос, выполоняя операцию "Команды" Выполнить(). "Команда" объявляет интерфейс для выполнения операции, "КонкретнаяКоманда" определяет связь между объектом "Получатель" и операцией Действие(), и, кроме того, реализует операцию Выполнить() путем вызова соответствующих операций объекта "Получатель". "Клиент" создает экземпляр класса "КонкретнаяКоманда" и устанавливает его получателя, "Инициатор" обращается к команде для выполнения запроса, "Получатель" (любой класс) располагает информацией о способах выполнения операций, необходимых для выполнения запроса.
|
Преимущества |
Паттерн "Команда" разрывает связь между объектом, инициирующим операции, и объектом, имеющим информацию о том, как ее выполнить, кроме того создается объект "Команда", который можно расширять и манипулировать им как объектом. |
3.2.4 Наблюдатель (Observer), Опубликовать - подписаться (Publish - Subscribe) или Delegation Event Model - GoF
Проблема |
Один объект ("Подписчик") должен знать об изменении состояний или некоторых событиях другого объекта. При этом необходимо поддерживать низкий уровень связывания с объектом - "Подписчиком". |
Решение |
Определить интерфейс "Подписки". Объекты - подписчики реализуют этот интерфейс и динамически регистрируются для получении информации о некотором событии. Затем при реализации условленного события оповещаются все объекты - подписчики. |
3.2.5 Не разговаривайте с неизвестными (Don't talk to strangers) - GRASP
Проблема |
Обеспечить связь клиентского объекта с непрямыми объектами (то есть известными другим объектам, а не самому клиенту). |
Решение |
Необходимо избегать проектных решений, предполагающих передачу сообщений с удаленными непрямыми объектами (незнакомцами). Решением может быть частный случай паттерна "Устойчивый к изменениям", см. 3.1.9. Прямым объектом потребуются новые операции. |
Преимущества |
Обеспечивает устойчивость системы к изменению структуры обьектов. |
3.2.6 Посетитель (Visitor) - GoF
Проблема |
Над каждым объектом некоторой структуры выполняется операция. Определить новую операцию, не изменяя классы обьектов. |
Решение |
Клиент, использующий данный паттерн, должен создать объект класса "КонкретныйПосетитель", а затем посетить каждый элемент структуры. "Посетитель" объявляет операцию "Посетить" для каждого класса "КонкретныйЭлемент" (имя и сигнатура данной операции идентифицируют класс, элемент которого посещает "Посетитель" - то есть, посетитель может обращаться к элементу напрямую). "КонкретныйПосетитель" реализует все операции, обьявленные в классе "Посетитель". Каждая операция реализует фрагмент алгоритма, определенного для класса соответствующего объекта в структуре.
Класс "КонкретныйПосетитель"предоставляет контекст для этого алгоритма и сохраняет его локальное состояние. "Элемент" определяет операцию "Принять", которая принимает "Посетителя" в качестве аргумента, "КонкретныйЭлемент" реализует операцию "Принять", которая принимает "Посетителя" в качестве аргумента. "СтруктураОбьекта" может перечислить свои аргументы и предоставить посетителю высокоуровневый интерфейс для посещения своих элементов.
|
Рекомендации |
Логично использовать, если в структуре присутствуют объекты многих классов с различными интерфейсами, и необходимо выполнить над ними операции, зависящие от конкретных классов, или если классы, устанавливающие структуру обьектов изменяются редко, но новые операции над этой структурой добавляются часто. |
Преимущества |
Упрощается добавление новых операций, объединяет родственные операции в классе "Посетитель". |
Недостатки |
Затруднено добавление новых классов "КонкретныйЭлемент", поскольку требуется объявление новой абстрактной операции в классе "Посетитель". |
3.2.7 Посредник (Mediator) - GoF
Проблема |
Обеспечить взаимодействие множества обьектов, сформировав при этом слабую связанность и избавив объекты от необходимости явно ссылаться друг на друга. |
Решение |
Создать объект инкапсулирующий способ взаимодействия множества обьектов. |
Пример |
"Посредник" определяет интерфейс для обмена информацией с объектами "Коллеги", "КонкретныйПосредник" координирует действия обьектов "Коллеги". Каждый класс "Коллеги" знает о своем объекте "Посредник", все "Коллеги" обмениваются информацией только с посредником, при его отсутствии им пришлось бы обмениваться информацией напрямую. "Коллеги" посылают запросы посреднику и получают запросы от него. "Посредник" реализует кооперативное поведения, пересылая каждый запрос одному или нескольким "Коллегам".
|
Преимущества |
Устраняется связанность между "Коллегами", централизуется управление. |
|
|