Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПИАПС / knigaVAPO_v2.doc
Скачиваний:
413
Добавлен:
17.04.2018
Размер:
35.96 Mб
Скачать

5.5. Структурные паттерны

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

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

При этом могут использоваться следующие механизмы:

  • Наследование, когда базовый класс определяет интерфейс, а подклассы - реализацию. Структуры на основе наследования получаются статичными.

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

Кратко рассмотрим особенности структрурных паттернов.

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

Паттерн Bridge отделяет абстракцию от реализации так, что то и другое можно изменять независимо.

Паттерн Composite группирует схожие объекты в древовидные структуры. Рассматривает единообразно простые и сложные объекты.

Паттерн Decorator используется для расширения функциональности объектов. Являясь гибкой альтернативой порождению классов, паттерн Decorator динамически добавляет объекту новые обязанности.

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

Паттерн Flyweight использует разделение для эффективной поддержки множества объектов.

Паттерн Proxy замещает другой объект для контроля доступа к нему.

5.5.1. Паттерн Адаптер, обертка (Adapter, wrapper)

Название и классификация паттерна

Адаптер - паттерн, структурирующий как классы, так и объекты.

Назначение паттерна Adapter

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

Паттерн Adapter, представляющий собой программную обертку над существующими классами, преобразует их интерфейсы к виду, пригодному для последующего использования.

Рассмотрим простейший пример применения паттерна Adapter. Пусть мы разрабатываем систему климат-контроля. Важным компонентом такой системы является температурный датчик, для которого уже имеется готовое программное обеспечение, представляющее собой некоторый класс с соответствующим интерфейсом для работы со шкалой Фаренгейта. Но нас интересует температура по шкале Цельсия. Задача может быть легко решеня с помощью паттерна Adapter.

Рассмотрим другой пример - графический редактор, в котором пользователи могут рисовать на экране графические элементы (линии, многоугольники, текст и т.д.) и организовывать их в виде картинок и диаграмм. Основной абстракцией графического редактора является графический объект, который имеет изменяемую форму и изображает сам себя. Интерфейс графических объектов определен абстрактным классом Shape. Редактор определяет подкласс класса Shape для каждого вида графических объектов: LineShape для прямых, PolygonShape для многоугольников и т.д.

Классы для элементарных геометрических фигур, например LineShape и PolygonShape, реализовать сравнительно просто, поскольку заложенные в них возможности рисования и редактирования крайне ограничены. Но подкласс Text Shape, умеющий отображать и редактировать текст, уже значительно сложнее. В то же время, существуют готовые библиотеки для разработки пользовательских интерфейсов, предоставляющие развитый класс Text View для отображения и редактирования текста.

Можно было бы так изменить интерфейс класса Text View, чтобы он соответствовал интерфейсу Shape, только для этого нужен исходный код. Но даже если он доступен, то вряд ли разумно изменять Text View - библиотека не должна приспосабливаться к интерфейсам каждого конкретного приложения.

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

Рисунок 40. UML-диаграмма адаптера объекта

На диаграмме (Рис. 41) показан адаптер объекта. Видно, как запрос BoundingBox, объявленный в классе Shape, преобразуется в запрос Get Extent, определенныйв классе Text View. Поскольку класс Text Shape адаптирует TextView к интерфейсу Shape, графический редактор может воспользоваться классом TextView, хотя тот и имеет несовместимый интерфейс.

Часто адаптер отвечает за функциональность, которую не может предоставить адаптируемый класс. На рис. 41 показано, как адаптер выполняет такого рода функции. У пользователя должна быть возможность перемещать любой объект класса Shape в другое место, но в классе TextView такая операция не предусмотрена. Text Shape может добавить недостающую функциональность, самостоятельно реализовав операцию CreateManipulator класса Shape, которая возвращает экземпляр подходящего подкласса Manipulator.

Manipulator - это абстрактный класс объектов, которым известно, как анимировать Shape в ответ на такие действия пользователя, как перетаскивание фигуры в другое место. У класса Manipulator имеются подклассы для различных фигур. Например, TextManipulator - подкласс для Text Shape. Возвращая экземпляр TextManipulator, объект класса TextShape добавляет новую функциональность, которой в классе TextView нет, а классу Shape требуется.

Применимость

Применяйте паттерн адаптер, когда:

  • хотите использовать существующий класс, но его интерфейс не соответствует вашим потребностям;

  • собираетесь создать повторно используемый класс, который должен взаимодействовать с заранее неизвестными или не связанными с ним классами, имеющими несовместимые интерфейсы;

  • (только для адаптера объектов!) нужно использовать несколько существующих подклассов, но непрактично адаптировать их интерфейсы путем порождения новых подклассов от каждого. В этом случае адаптер объектов может приспосабливать интерфейс их общего родительского класса.

Описание паттерна Adapter

Адаптер класса использует множественное наследование для адаптации одного интерфейса к другому.

Пусть класс, интерфейс которого нужно адаптировать к нужному виду, имеет имя Adaptee. Для решения задачи преобразования его интерфейса паттерн Adapter вводит следующую иерархию классов:

  • Виртуальный базовый класс Target. Здесь объявляется пользовательский интерфейс подходящего вида. Только этот интерфейс доступен для пользователя.

  • Производный класс Adapter, реализующий интерфейс Target. В этом классе также имеется указатель или ссылка на экземпляр Adaptee. Паттерн Adapter использует этот указатель для перенаправления клиентских вызовов в Adaptee. Так как интерфейсы Adaptee и Target несовместимы между собой, то эти вызовы обычно требуют преобразования.

Структура

Рисунок 41. UML-диаграмма классов паттерна Adapter

Соседние файлы в папке ПИАПС