Шаблон проектирования Мост (Bridge Pattern) - описание, статья

Рассмотрим шаблон проектирования Мост

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

Мост - относится к группе структурных паттернов.

Назначение

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

Псевдоним

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

Мотивация

Предполоижим, что:

  1. мы создаём библиотеку, для отображения элементов пользовательского интерфейса (окна, маленькие изображения "около часов" и т.д.)
  2. эта библиотека должна работать на разных платформах

В связи со вторым пунктом - мы могли бы использовать наследование от некоторого общего прообраза "окна" (общего для всех виджетов) и реализовать в подклассах конкрентую реализацию для нашей платформы - в этом случае нам пришлось бы:

  1. реализовать для каждой платформы столько подклассов, сколько у нас виджетов (разных типом - т.е. - главное окно, малое окно, значок трея и т.д.)
  2. в клиенском коде пришлось бы определять в какой системе мы находимся и инстацировать уже конкретный подкласс для данный платформы (системы).

Здесь, опять же - особенно важен второй пункт - мало того, что мы создаём классы с жёстко заданным интерфейсом (что может затруднить "повторное" использование библиотеки в целом), мы ещё и вынуждены в клиентском коде опрелять - какой именно класс требуется инстацировать.

Процесс быстрого (и "проблемного" с точки зрения паттерна Мост) "разростания" иерархии конкретных реализаций приведён на изображении ниже:
паттернм мост - мотивация - иерархии - шаблон

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

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

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

  1. хотите избежать постоянной привязки абстракции к реализации. Так, например, бывает, когда реализацию необходимо выбирать во время выполнения программы;
  2. абстракции, и реализации должны расширяться новыми подклассами. В таком случае паттерн мост позволяет комбинировать разные абстракции и реализации и изменять их независимо;
  3. изменения в реализации абстракции не должны сказываться на клиентах, то есть клиентский код не должен перекомпилироваться;
  4. (только для C++!) вы хотите полностью скрыть от клиентов реализацию абстракции. В C++ представление класса видимо через его интерфейс;
  5. число классов начинает быстро расти (что создаёт проблему), как мы видели на первой диаграмме из раздела«Мотивация». Это признак того, что иерархию следует разделить на две части. Для таких иерархий классов Рамбо( Rumbaugh) использует термин «вложенные обобщения»[RBP+91];
  6. вы хотите разделить одну реализацию между несколькими объектами (быть может, применяя подсчет ссылок), и этот факт необходимо скрыть от клиента. Простой пример - это разработанный Джеймсом Коплиеном класс String [Сор92], в котором разные объекты могут разделять одно и то же представление строки (StringRep).

Структура

Структура паттерна мост может быть представлена следующей схемой:
мост паттерн шаблон структура

Участники

  1. Abstraction(Window) - абстракция: определяет интерфейс абстракции; хранит ссылку на объект типа Implementor;
  2. RefinedAbstraction(iconWindow) - уточненная абстракция: расширяет интерфейс, определенный абстракцией Abstraction;
  3. Implementor(Windowlmp) реализатор: определяет интерфейс для классов реализации. Он не обязан точно соответствовать интерфейсу класса Abstraction. На самом деле оба интерфейса могут быть совершенно различны. Обычно интерфейс класса Implementor предоставляет только примитивные операции, а класс Abstraction определяет операции более высокого уровня, базирующиеся на этих примитивах;
  4. Concretelmplementor(XWindowlmp,PMWindowlmp) - конкретный реализатор - содержит конкретную реализацию интерфейса класса Implementor.

Отношения

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

Результаты

Результаты применения паттерна мост таковы:

  1. отделение реализации от интерфейса. Реализация больше не имеет постоянной привязки к интерфейсу. Реализацию абстракции можно конфигурировать во время выполнения. Объект может даже динамически изменять свою реализацию.
  2. Разделение классов Abstraction и Implementor устраняет также зависимости от реализации, устанавливаемые на этапе компиляции.
    Чтобы изменить класс реализации, вовсе не обязательно перекомпилировать класс Abstraction и его клиентов. Это свойство особенно важно, если необходимо обеспечить двоичную совместимость между разными версиями библиотеки классов. Кроме того, такое разделение облегчает разбиение системы на слои и тем самым позволяет улучшить ее структуру.

    Высокоуровневые части системы должны знать только о классах Abstraction и Implementor;

  3. повышение степени расширяемости. Можно расширять независимо иерархии классовAbstraction иImplementor;
  4. сокрытие деталей реализации от клиентов. Клиентов можно изолировать от таких деталей реализации, как разделение объектов класса Implementor и сопутствующего механизма подсчета ссылок.

Реализация

Вопросы, над которыми следует поразмылить в случае, если вы решились применять паттерн мост:

  1. только один класс Implementor.

1) только один класс Implementor.

В ситуациях, когда есть только одна реализация, создавать абстрактный класс Implementor необязательно. Это вырожденный случай паттерна мост3 между классами Abstraction и Implementor существует взаимно-однозначное соответствие. Тем не менее разделение все же полезно, если нужно, чтобы изменение реализации класса
не отражалось на существующих клиентах(должно быть достаточно заново
скомпоновать программу, не перекомпилируя клиентский код).
Для описания такого разделения Каролан(Carolan)[Car89] употребляет сочетание «чеширский кот». В C++ интерфейс класса Implementor можно определить в закрытом заголовочном файле, который не передается клиентам. Это позволяет полностью скрыть реализацию класса от клиентов;

Пример кода

Рассмотрим такой вот пример кода паттерна Мост на PHP.

Известные применения

Много где, ясное дело =)

В библиотеке libg++ [Lea88]

Родственные паттерны

Паттерн абстрактная фабрика может создать и сконфигурировать мост.

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

Key Words for FKN + antitotal forum (CS VSU):