Образец моста - Bridge pattern

В образец моста это шаблон дизайна используется в программная инженерия это предназначено для "развязать абстракция из его реализация так что оба могут изменяться независимо ", представленный Банда четырех.[1] В мост использует инкапсуляция, агрегирование, и может использовать наследство разделить обязанности на разные классы.

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

Когда есть только одна фиксированная реализация, этот шаблон известен как Pimpl идиома в C ++ Мир.

Образец моста часто путают с шаблон адаптера, и часто реализуется с помощью шаблон адаптера объекта; например, в коде Java ниже.

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

Обзор

Мост [2]шаблон дизайна - один из двадцати трех хорошо известных Шаблоны проектирования GoF которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать.

Какие проблемы может решить шаблон проектирования Bridge?[3]

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

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

Какое решение описывает шаблон проектирования Bridge?

  • Отделить абстракцию (Абстракция) от его реализации (Разработчик), поместив их в отдельные иерархии классов.
  • Реализовать Абстракция с точки зрения (делегируя) Разработчик объект.

Это позволяет настроить Абстракция с Разработчик объект во время выполнения.
См. Также Единый язык моделирования диаграмма классов и последовательности ниже.

Структура

Схема классов и последовательности UML

Пример класса UML и диаграммы последовательности для шаблона проектирования Bridge. [4]

В указанном выше унифицированном языке моделирования диаграмма классов, абстракция (Абстракция) не реализована как обычно в одной иерархии наследования. Вместо этого существует одна иерархия для абстракции (Абстракция) и отдельная иерархия для его реализации (Разработчик), что делает их независимыми друг от друга. Абстракция интерфейс (операция ()) реализуется в виде (путем делегирования) Разработчик интерфейс (imp.operationImp ()).
В UML схема последовательности показывает взаимодействия во время выполнения: Абстракция1 объект делегирует реализацию Реализатор1 объект (позвонив operationImp () на Реализатор1), который выполняет операцию и возвращается к Абстракция1.

Диаграмма классов

Схема классов Bridge UML.svg

Абстракция (абстрактный класс)
определяет абстрактный интерфейс
поддерживает ссылку на исполнителя.
RefinedAbstraction (обычный класс)
расширяет интерфейс, определенный абстракцией
Разработчик (интерфейс)
определяет интерфейс для классов реализации
ConcreteImplementor (обычный класс)
реализует интерфейс Implementor
Мост в LePUS3 (легенда )

пример

C #

Мостовой узор объединяет объекты в древовидную структуру. Он отделяет абстракцию от реализации. Здесь абстракция представляет клиента, из которого будут вызываться объекты. Пример, реализованный на C #, приведен ниже.

// Помогает обеспечить действительно независимую архитектуруобщественный интерфейс IBridge{    пустота Функция1();    пустота Функция2();}общественный класс Мост1 : IBridge{    общественный пустота Функция1()    {        Консоль.WriteLine("Мост1.Функция1");    }    общественный пустота Функция2()    {        Консоль.WriteLine("Мост1.Функция2");    }}общественный класс Мост2 : IBridge{    общественный пустота Функция1()    {        Консоль.WriteLine("Мост2.Функция1");    }    общественный пустота Функция2()    {        Консоль.WriteLine("Мост2.Функция2");    }}общественный интерфейс IAbstractBridge{    пустота CallMethod1();    пустота CallMethod2();}общественный класс АннотацияМост : IAbstractBridge{    общественный IBridge мост;    общественный АннотацияМост(IBridge мост)    {        этот.мост = мост;    }    общественный пустота CallMethod1()    {        этот.мост.Функция1();    }    общественный пустота CallMethod2()    {        этот.мост.Функция2();    }}

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

Кристалл

Абстрактные класс DrawingAPI  Абстрактные def draw_circle(Икс : Float64, у : Float64, радиус : Float64)конецкласс РисунокAPI1 < DrawingAPI  def draw_circle(Икс : Плавать, у : Плавать, радиус : Плавать)    "API1.circle at #{Икс}:#{у} - радиус: #{радиус}"  конецконецкласс РисунокAPI2 < DrawingAPI  def draw_circle(Икс : Float64, у : Float64, радиус : Float64)    "API2.circle at #{Икс}:#{у} - радиус: #{радиус}"  конецконецАбстрактные класс Форма  защищенный добытчик drawing_api : DrawingAPI  def инициализировать(@drawing_api)  конец  Абстрактные def привлечь  Абстрактные def resize_by_percentage(процент : Float64)конецкласс CircleShape < Форма  добытчик Икс : Float64  добытчик у : Float64  добытчик радиус : Float64  def инициализировать(@Икс, @y, @радиус, drawing_api : DrawingAPI)    супер(drawing_api)  конец  def привлечь    @drawing_api.draw_circle(@Икс, @y, @радиус)  конец  def resize_by_percentage(процент : Float64)    @радиус *= (1 + процент/100)  конецконецкласс Мост  def я.тестовое задание    формы = [] из Форма    формы << CircleShape.новый(1.0, 2.0, 3.0, РисунокAPI1.новый)    формы << CircleShape.новый(5.0, 7.0, 11.0, РисунокAPI2.новый)    формы.каждый делать |форма|      форма.resize_by_percentage(2.5)      ставит форма.привлечь    конец  конецконецМост.тестовое задание

Вывод

API1.circle в 1.0: 2.0 - радиус: 3.075API2.circle в 5.0: 7.0 - радиус: 11.275

C ++

#включают <iostream>#включают <string>#включают <vector>класс DrawingAPI {  общественный:    виртуальный ~DrawingAPI() = по умолчанию;    виртуальный стандартное::строка DrawCircle(плавать Икс, плавать у, плавать радиус) const = 0;};класс РисунокAPI01 : общественный DrawingAPI {  общественный:    стандартное::строка DrawCircle(плавать Икс, плавать у, плавать радиус) const отменять {      вернуть "API01.circle at" + стандартное::нанизывать(Икс) + ":" + стандартное::нанизывать(у) +        "- радиус:" + стандартное::нанизывать(радиус);     }};класс РисунокAPI02 : общественный DrawingAPI {  общественный:    стандартное::строка DrawCircle(плавать Икс, плавать у, плавать радиус) const отменять {      вернуть "API02.circle at" + стандартное::нанизывать(Икс) + ":" + стандартное::нанизывать(у) +        "- радиус:" + стандартное::нанизывать(радиус);     }};класс Форма {  общественный:    Форма(const DrawingAPI& drawing_api) : drawing_api_(drawing_api) {}    виртуальный ~Форма() = по умолчанию;    виртуальный стандартное::строка Привлечь() const = 0;    виртуальный плавать ResizeByPercentage(const плавать процент) = 0;  защищенный:    const DrawingAPI& drawing_api_;};класс CircleShape: общественный Форма {  общественный:        CircleShape(плавать Икс, плавать у, плавать радиус, const DrawingAPI& drawing_api)      : Форма(drawing_api), Икс_(Икс), y_(у), радиус_(радиус) {}    стандартное::строка Привлечь() const отменять {        вернуть drawing_api_.DrawCircle(Икс_, y_, радиус_);    }    плавать ResizeByPercentage(const плавать процент) отменять {      вернуть радиус_ *= (1.0f + процент/100.0f);    }    частный:    плавать Икс_, y_, радиус_;};int основной(int argc, char** argv) {  стандартное::вектор<CircleShape> формы {    CircleShape{1.0f, 2.0f, 3.0f, РисунокAPI01{}},    CircleShape{5.0f, 7.0f, 11.0f, РисунокAPI02{}}  };   для (авто& форма: формы) {    форма.ResizeByPercentage(2.5);    стандартное::cout << форма.Привлечь() << стандартное::конец;  }  вернуть 0;}

Вывод:

API01.circle в точке 1.000000: 2.000000 - радиус: 3.075000API02.circle в точке 5.000000: 7.000000 - радиус: 11.275000

Ява

Следующее Ява Программа определяет банковский счет, который отделяет операции по счету от регистрации этих операций.

// У Logger есть две реализации: информация и предупреждение@FunctionalInterfaceинтерфейс Регистратор {    пустота журнал(Строка сообщение);        статический Регистратор Информация() {        вернуть сообщение -> Система.вне.println("Информация: " + сообщение);    }    статический Регистратор предупреждение() {        вернуть сообщение -> Система.вне.println("предупреждение:" + сообщение);    }}Абстрактные класс AbstractAccount {    частный Регистратор регистратор = Регистратор.Информация();        общественный пустота setLogger(Регистратор регистратор) {        этот.регистратор = регистратор;    }        // часть ведения журнала делегируется реализации Logger    защищенный пустота работать(Строка сообщение, логический результат) {        регистратор.журнал(сообщение + "результат" + результат);    }}класс SimpleAccount расширяет AbstractAccount {    частный int остаток средств;        общественный SimpleAccount(int остаток средств) {        этот.остаток средств = остаток средств;    }        общественный логический isBalanceLow() {        вернуть остаток средств < 50;    }        общественный пустота изымать(int количество) {        логический shouldPerform = остаток средств >= количество;        если (shouldPerform) {            остаток средств -= количество;        }        работать("изымать " + количество, shouldPerform);    }}общественный класс МостДемо {    общественный статический пустота основной(Строка[] аргументы) {        SimpleAccount учетная запись = новый SimpleAccount(100);        учетная запись.изымать(75);                если (учетная запись.isBalanceLow()) {            // вы также можете изменить реализацию Logger во время выполнения            учетная запись.setLogger(Регистратор.предупреждение());        }                учетная запись.изымать(10);        учетная запись.изымать(100);    }}

Он выведет:

информация: отозвать 75 результатов truewarning: отозвать 10 результатов Trueewarning: отозвать 100 результат false

PHP

интерфейс DrawingAPI{    функция drawCircle($ x, $ y, $ radius);}класс РисунокAPI1 орудия DrawingAPI{    общественный функция drawCircle($ x, $ y, $ radius)    {        эхо "API1.circle at $ x:$ y радиус $ radius. п";    }}класс РисунокAPI2 орудия DrawingAPI{    общественный функция drawCircle($ x, $ y, $ radius)    {        эхо "API2.circle at $ x:$ y радиус $ radius. п";    }}Абстрактные класс Форма{    защищенный $ drawingAPI;    общественный Абстрактные функция привлечь();    общественный Абстрактные функция resizeByPercentage($%);    защищенный функция __construct(DrawingAPI $ drawingAPI)    {        $ это->рисунокAPI = $ drawingAPI;    }}класс CircleShape расширяет Форма{    частный $ x;    частный $ y;    частный $ radius;    общественный функция __construct($ x, $ y, $ radius, DrawingAPI $ drawingAPI)    {        родитель::__construct($ drawingAPI);        $ это->Икс = $ x;        $ это->у = $ y;        $ это->радиус = $ radius;    }    общественный функция привлечь()    {        $ это->рисунокAPI->drawCircle($ это->Икс, $ это->у, $ это->радиус);    }    общественный функция resizeByPercentage($%)    {        $ это->радиус *= $%;    }}класс Тестер{    общественный статический функция основной()    {        $ shape = массив(            новый CircleShape(1, 3, 7,  новый РисунокAPI1()),            новый CircleShape(5, 7, 11, новый РисунокAPI2()),        );        для каждого ($ shape так как $ shape) {            $ shape->resizeByPercentage(2.5);            $ shape->привлечь();        }    }}Тестер::основной();

Вывод:

API1.circle с радиусом 1: 3 17,5 API2.circle с радиусом 5: 7 27,5

Scala

черта характера DrawingAPI {  def drawCircle(Икс: Двойной, у: Двойной, радиус: Двойной)}класс РисунокAPI1 расширяет DrawingAPI {  def drawCircle(Икс: Двойной, у: Двойной, радиус: Двойной) = println(s "API №1 $ x$ y$ radius")}класс РисунокAPI2 расширяет DrawingAPI {  def drawCircle(Икс: Двойной, у: Двойной, радиус: Двойной) = println(s "API №2 $ x$ y$ radius")}Абстрактные класс Форма(рисунокAPI: DrawingAPI) {  def привлечь()  def resizePercentage(процент: Двойной)}класс CircleShape(Икс: Двойной, у: Двойной, вар радиус: Двойной, рисунокAPI: DrawingAPI)    расширяет Форма(рисунокAPI: DrawingAPI) {  def привлечь() = рисунокAPI.drawCircle(Икс, у, радиус)  def resizePercentage(процент: Двойной) { радиус *= процент }}объект Мост {  def основной(аргументы: Массив[Строка]) {    Seq (	новый CircleShape(1, 3, 5, новый РисунокAPI1),	новый CircleShape(4, 5, 6, новый РисунокAPI2)    ) для каждого { Икс =>        Икс.resizePercentage(3)        Икс.привлечь()			      }	  }}

Python

"""Пример схемы моста."""от abc импорт ABCMeta, абстрактный методНЕ РЕАЛИЗОВАНА = «Вы должны реализовать это».класс DrawingAPI:    __metaclass__ = ABCMeta    @abstractmethod    def draw_circle(я, Икс, у, радиус):        поднять NotImplementedError(НЕ РЕАЛИЗОВАНА)класс РисунокAPI1(DrawingAPI):    def draw_circle(я, Икс, у, радиус):        вернуть ж"API1.circle at {Икс}:{y} - радиус: {радиус}"класс РисунокAPI2(DrawingAPI):    def draw_circle(я, Икс, у, радиус):        вернуть ж"API2.circle at {Икс}:{y} - радиус: {радиус}"класс РисованиеAPI3(DrawingAPI):    def draw_circle(я, Икс, у, радиус):        вернуть ж"API3.circle at {Икс}:{y} - радиус: {радиус}"класс Форма:    __metaclass__ = ABCMeta    drawing_api = Никто    def __в этом__(я, drawing_api):        я.drawing_api = drawing_api    @abstractmethod    def привлечь(я):        поднять NotImplementedError(НЕ РЕАЛИЗОВАНА)    @abstractmethod    def resize_by_percentage(я, процент):        поднять NotImplementedError(НЕ РЕАЛИЗОВАНА)класс CircleShape(Форма):    def __в этом__(я, Икс, у, радиус, drawing_api):        я.Икс = Икс        я.у = у        я.радиус = радиус        супер(CircleShape, я).__в этом__(drawing_api)    def привлечь(я):        вернуть я.drawing_api.draw_circle(я.Икс, я.у, я.радиус)    def resize_by_percentage(я, процент):        я.радиус *= 1 + процент / 100класс Мост:    @staticmethod    def тестовое задание():        формы = [            CircleShape(1.0, 2.0, 3.0, РисунокAPI1()),            CircleShape(5.0, 7.0, 11.0, РисунокAPI2()),            CircleShape(5.0, 4.0, 12.0, РисованиеAPI3()),        ]        для форма в формы:            форма.resize_by_percentage(2.5)            Распечатать(форма.привлечь())Мост.тестовое задание()

Смотрите также

использованная литература

  1. ^ Гамма, E, Хелм, R, Джонсон, R, Влиссидес, J: Шаблоны проектирования, стр. 151. Эддисон-Уэсли, 1995.
  2. ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Паттерны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования. Эддисон Уэсли. стр.151ff. ISBN  0-201-63361-2.CS1 maint: несколько имен: список авторов (ссылка на сайт)
  3. ^ «Шаблон проектирования моста - проблема, решение и применимость». w3sDesign.com. Получено 2017-08-12.
  4. ^ «Шаблон проектирования моста - структура и взаимодействие». w3sDesign.com. Получено 2017-08-12.

внешние ссылки