Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник.pdf
Скачиваний:
2
Добавлен:
10.06.2024
Размер:
3.87 Mб
Скачать

Рис. 12.48. Динамическая составляющая паттерна Наблюдатель

Результаты. Субъекту известно только об абстрактном наблюдателе, он ничего не знает о конкретных наблюдателях. В результате между этими объектами устанавливается минимальное сцепление (это достоинство). Изменения в субъекте могут привести к неоправданно большому количеству обновлений наблюдателей — ведь наблюдателю неизвестно, что именно изменилось в субъекте, затрагивают ли его произошедшие изменения (это недостаток).

Обозначение паттерна Наблюдатель приведено на рис. 12.49, где показано, что у него два параметра настройки — субъект и наблюдатель.

Рис. 12.49. Обозначение паттерна Наблюдатель

Эти параметры обозначают роли, которые будут играть конкретные классы, используемые при настройке паттерна на конкретное применение. Например, настройку паттерна на отображение текущего фильма кинофестиваля иллюстрирует рис. 12.50.

Рис. 12.50. Настройка паттерна Наблюдатель

Видим, что подключаемые конкретные классы (Кинопрограмма, Текущий фильм) соединяются с символом паттерна пунктирными линиями. Каждая пунктирная линия подписана ролью (именем параметра), которую играет конкретный класс в формируемой кооперации. Таким образом, в данном случае класс Кинопрограмма становится подклассом абстрактного класса Субъект в паттерне, а класс Текущий фильм — подклассом абстрактного класса Наблюдатель в паттерне.

Паттерн Компоновщик

Паттерн Компоновщик (Composite) обеспечивает представление иерархий часть-целое, объединяя объекты в древовидные структуры.

Проблема. Очень часто возникает необходимость создавать маленькие компоненты (примитивы), объединять их в более крупные компоненты (контейнеры), более крупные компоненты соединять в большие компоненты, большие компоненты — в огромные и т. д. При этом клиентам приходится различать компоненты-примитивы и компоненты-контейнеры, работать с ними по-разному. Это усложняет приложение. Паттерн Компоновщик позволяет ликвидировать это различие, его можно применять в следующих случаях:

166

необходимо построить иерархию объектов вида часть-целое;

нужно унифицировать использование как составных, так и индивидуальных объектов.

Решение. Ключевым элементом решения является абстрактный класс Компонент, который является одновременно и примитивом, и контейнером. В нем объявлены:

абстрактная операция примитива Работать( );

абстрактные операции контейнера — управления примитивами-потомками

Добавить(Компонент) и Удалить(Компонент), а также доступа к потомку Получить-Потомка().

Структурная составляющая паттерна Компоновщик представлена на рис. 12.51.

Рис. 12.51. Структурная составляющая паттерна Компоновщик

Из рисунка видно, что с помощью паттерна организуется рекурсивная композиция.

Класс Компонент служит простым элементом дерева, класс Компоновщик является рекурсивным элементом, а класс Лист — конечным элементом дерева. Класс Компонент служит родителем классов Лист и Компоновщик. Отметим, что класс Компоновщик является агрегатом составных частей — экземпляров класса Компонент (таким образом задается рекурсия).

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

Результаты. Паттерн определяет иерархии, состоящие из классов-примитивов и классовконтейнеров, облегчает добавление новых разновидностей компонентов. Он упрощает организацию клиентов (клиент не должен учитывать специфику адресуемого объекта). Недостаток применения паттерна — трудность в наложении ограничений на объекты, которые можно включать в композицию.

Обозначение паттерна Компоновщик приведено на рис. 12.52, где показано, что у него три параметра настройки — компонент, компоновщик и лист.

Настройку паттерна на графическое приложение иллюстрирует рис. 12.53.

Рис. 12.52. Обозначение паттерна Компоновщик

167

Рис. 12.53. Настройка паттерна Компоновщик

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

Паттерн Команда

Паттерн Команда (Command) выполняет преобразование запроса в объект, обеспечивая:

параметризацию клиентов с различными запросами;

постановку запросов в очередь и их регистрацию;

поддержку отмены операций.

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

объекты параметризируются действием. В процедурных языках параметризация осуществляется при помощи функции обратного вызова, которая регистрируется для последующего вызова. Паттерн Команда предлагает объектно-ориентированную замену функций обратного вызова;

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

необходимо регистрировать изменения состояния для восстановления системы в случае аварийного отказа;

необходимо создание сложных операций, которые строятся на основе примитивных операций. Решение. Основным элементом решения является абстрактный класс Команда, обеспечивающий

одну абстрактную операцию Выполнять(). Конкретные подклассы этого класса реализуют операцию Выполнять(). Они задают пару получатель-действие. Получатель запоминается в экземплярной переменной подкласса. Запрос получателю посылается в ходе исполнения конкретной операции Выполнять().

Структурная составляющая паттерна Команда показана на рис. 12.54. Классы этой структуры имеют следующие обязанности:

Команда объявляет интерфейс для выполнения операции;

КонкрКоманда определяет связь между экземпляром класса Получатель и действием, реализует Выполнять(), вызывая нужную операцию получателя;

Клиент создает объект класса КонкрКоманда и устанавливает его получателя;

Инициатор просит команду выполнить запрос;

Получатель умеет выполнять запрашиваемые операции.

Рис. 12.54. Структурная составляющая паттерна Команда

В качестве конкретной команды могут выступать команда Открыть, команда Вставить. Инициатором может быть Пункт Меню, а получателем — Документ.

168

Соседние файлы в предмете Технология программирования