Образец моста - Bridge pattern
В образец моста это шаблон дизайна используется в программная инженерия это предназначено для "развязать абстракция из его реализация так что оба могут изменяться независимо ", представленный Банда четырех.[1] В мост использует инкапсуляция, агрегирование, и может использовать наследство разделить обязанности на разные классы.
Когда класс часто меняется, особенности объектно-ориентированного программирования стали очень полезными, потому что изменения в программа с код можно легко сделать с минимальными предварительными знаниями о программе. Шаблон моста полезен, когда и класс, и его действия часто меняются. Сам класс можно рассматривать как абстракция и что может делать класс в качестве реализация. Образец моста также можно рассматривать как два уровня абстракции.
Когда есть только одна фиксированная реализация, этот шаблон известен как Pimpl идиома в C ++ Мир.
Образец моста часто путают с шаблон адаптера, и часто реализуется с помощью шаблон адаптера объекта; например, в коде Java ниже.
Вариант: реализация может быть еще больше отделена, отложив присутствие реализации до точки, в которой используется абстракция.
Обзор
Мост [2]шаблон дизайна - один из двадцати трех хорошо известных Шаблоны проектирования GoF которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, протестировать и повторно использовать.
Какие проблемы может решить шаблон проектирования Bridge?[3]
- Абстракция и ее реализация должны определяться и расширяться независимо друг от друга.
- Следует избегать привязки во время компиляции между абстракцией и ее реализацией, чтобы реализацию можно было выбрать во время выполнения.
При использовании подклассов разные подклассы реализуют абстрактный класс по-разному. Но реализация привязана к абстракции во время компиляции и не может быть изменена во время выполнения.
Какое решение описывает шаблон проектирования Bridge?
- Отделить абстракцию (
Абстракция
) от его реализации (Разработчик
), поместив их в отдельные иерархии классов. - Реализовать
Абстракция
с точки зрения (делегируя)Разработчик
объект.
Это позволяет настроить Абстракция
с Разработчик
объект во время выполнения.
См. Также Единый язык моделирования диаграмма классов и последовательности ниже.
Структура
Схема классов и последовательности UML
В указанном выше унифицированном языке моделирования диаграмма классов, абстракция (Абстракция
) не реализована как обычно в одной иерархии наследования. Вместо этого существует одна иерархия для абстракции (Абстракция
) и отдельная иерархия для его реализации (Разработчик
), что делает их независимыми друг от друга. Абстракция
интерфейс (операция ()
) реализуется в виде (путем делегирования) Разработчик
интерфейс (imp.operationImp ()
).
В UML схема последовательности показывает взаимодействия во время выполнения: Абстракция1
объект делегирует реализацию Реализатор1
объект (позвонив operationImp ()
на Реализатор1
), который выполняет операцию и возвращается к Абстракция1
.
Диаграмма классов
- Абстракция (абстрактный класс)
- определяет абстрактный интерфейс
- поддерживает ссылку на исполнителя.
- RefinedAbstraction (обычный класс)
- расширяет интерфейс, определенный абстракцией
- Разработчик (интерфейс)
- определяет интерфейс для классов реализации
- ConcreteImplementor (обычный класс)
- реализует интерфейс Implementor
пример
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) Распечатать(форма.привлечь())Мост.тестовое задание()
Смотрите также
использованная литература
- ^ Гамма, E, Хелм, R, Джонсон, R, Влиссидес, J: Шаблоны проектирования, стр. 151. Эддисон-Уэсли, 1995.
- ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Паттерны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования. Эддисон Уэсли. стр.151ff. ISBN 0-201-63361-2.CS1 maint: несколько имен: список авторов (ссылка на сайт)
- ^ «Шаблон проектирования моста - проблема, решение и применимость». w3sDesign.com. Получено 2017-08-12.
- ^ «Шаблон проектирования моста - структура и взаимодействие». w3sDesign.com. Получено 2017-08-12.
внешние ссылки
- Мост в UML и LePUS3 (формальный язык моделирования)
- Шаблоны проектирования C #: шаблон моста. Образец главы. 2002-12-20. От: Джеймс В. Купер (2003). Шаблоны проектирования C #: Учебное пособие. Эддисон-Уэсли. ISBN 0-201-84453-2.