Название и классификация паттерна
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

Мост - паттерн, структурирующий объекты

Назначение

Отделить абстракцию от ее реализации так, чтобы то и другое можно было

изменять независимо.

Известен также под именем

Handle/Body (описатель/тело).

Bridge: мотивация

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

Рассмотрим реализацию переносимой абстракции окна в библиотеке для разработки пользовательских интерфейсов. Написанные с ее помощью приложения должны работать в разных средах, например под X Window System и Presentation Manager (PM) от компании IBM. С помощью наследования мы могли бы определить абстрактный класс Window и его подклассы XWindow и PMWindow, реализующие интерфейс окна для разных платформ. Но у такого решения есть два недостатка:

1) неудобно распространять абстракцию Window на другие виды окон или новые платформы. Представьте себе подкласс IconWindow, который специализирует абстракцию окна для пиктограмм. Чтобы поддержать пиктограммы на обеих платформах, нам придется реализовать два новых подкласса XlconWindow и PMIconWindow. Более того, по два подкласса необходимо определять для каждого вида окон. А для поддержки третьей платформы придется определять для всех видов окон новый подкласс Window;

2) клиентский код становится платформенно-зависимым. При создании окна клиент инстанцирует конкретный класс, имеющий вполне определенную реализацию. Например, создавая объект XWindow, мы привязываем абстракцию окна к ее реализации для системы X Window и, следовательно, делаем код клиента ориентированным именно на эту оконную систему. Таким образом, усложняется перенос клиента на другие платформы. Клиенты должны иметь возможность создавать окно, не привязываясь к конкретной реализации. Только сама реализация окна должна зависеть от платформы, на которой работает приложение. Поэтому в клиентском коде неможет быть никаких упоминаний о платформах.

Рисунок 12

С помощью паттерна мост эти проблемы решаются. Абстракция окна и ее реализация помещаются в раздельные иерархии классов. Таким образом, существует одна иерархия для интерфейсов окон (Window, IconWindow, TransientWindow) и другая (с корнем Windowimp) - для платформенно-зависимых реализаций. Так, подкласс XWindowImp предоставляет реализацию в системе X Window System.

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

Рисунок 13

Bridge: применимость

Используйте паттерн мост, когда:

1. хотите избежать постоянной привязки абстракции к реализации. Так, например, бывает, когда реализацию необходимо выбирать во время выполнения программы;

2. и абстракции, и реализации должны расширяться новыми подклассами. В таком случае паттерн мост позволяет комбинировать разные абстракции и реализации и изменять их независимо;

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

4. только для C++! Вы хотите полностью скрыть от клиентов реализацию абстракции. В C++ представление класса видимо через его интерфейс;

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

6. вы хотите разделить одну реализацию между несколькими объектами (быть может, применяя подсчет ссылок), и этот факт необходимо скрыть от клиента.

Bridge: структура

Рисунок 14

Участники

Abstraction (Window) – абстракция - определяет интерфейс абстракции и хранит ссылку на объект типа Implementor;

RefinedAbstraction (iconWindow) – уточненная абстракция - расширяет интерфейс, определенный абстракцией Abstraction;

Implementor (Windowlmp) – реализатор - определяет интерфейс для классов реализации. Он не обязан точно соответствовать интерфейсу класса Abstraction. На самом деле оба интерфейса могут быть совершенно различны. Обычно интерфейс класса Implementor предоставляет только примитивные операции, а класс Abstraction определяет операции более высокого уровня, базирующиеся на этих примитивах;

Concretelmplementor ( XWindowlmp , PMWindowlmp ) – конкретный реализатор - содержит конкретную реализацию интерфейса класса Implementor.

Отношения

Объект Abstraction перенаправляет своему объекту Implementor запросы клиента.

Реализация

1. Только один класс Implementor. В ситуациях, когда есть только одна реализация, создавать абстрактный класс Implementor необязательно. Это вырожденный случай паттерна мост- между классами Abstraction и Implementor существует взаимно-однозначное соответствие. Тем не менее,разделение все же полезно, если нужно, чтобы изменение реализации класса не отражалось на существующих клиентах (должно быть достаточно зановоскомпоновать программу, не перекомпилируя клиентский код). Например, в C++ интерфейс класса Implementor можно определить в закрытом заголовочном файле, который не передается клиентам. Это позволяет полностью скрыть реализацию класса от клиентов.

2. Создание правильного объекта Implementor. Как, когда и где принимается решение о том, какой из нескольких классов Implementor инстанцировать? Если у класса Abstraction есть информация о конкретных классах Concretelmplementor, то он может инстанцировать один из них в своем конструкторе; какой именно - зависит от переданных конструктору параметров. Так, если класс коллекции поддерживает несколько реализаций, то решение можно принять в зависимости от размера коллекции. Для небольших коллекций применяется реализация в виде связанного списка, для больших - в виде хэшированных таблиц. Другой подход - заранее выбрать реализацию по умолчанию, а позже изменять ее в соответствии с тем, как она используется. Например, если число элементов в коллекции становится больше некоторой условной величины, то мы переключаемся с одной реализации на другую, более эффективную. Можно также делегировать решение другому объекту. В примере с иерархиями Window/Windowlmp уместно было бы ввести фабричный объект, единственная задача которого - инкапсулировать платформенную специфику. Фабрика обладает информацией, объекты Windowlmp какого вида надо создавать для данной платформы, а объект Window просто обращается к ней с запросом о предоставлении какого-нибудь объекта Windowlmp, при этом понятно, что объект получит то, что нужно. Преимущество описанного подхода: класс Abstraction напрямую непривязан ни к одному из классов Imp lament or;

3. Разделение реализаторов. В C++ можно применить идиому описатель/тело, чтобы несколькими объектами могла совместно использоваться одна и та же реализация. В теле хранится счетчик ссылок, который увеличивается и уменьшается в классе описателя.

Паттерн Composite.

Дата: 2019-02-25, просмотров: 212.