Шаблон моста — это шаблон проектирования , используемый в программной инженерии , который призван «разделить абстракцию от ее реализации так, чтобы они могли изменяться независимо» , введенный «Бандой четырех». [1] Мост использует инкапсуляцию , агрегацию и может использовать наследование для разделения обязанностей по разным классам .
Когда класс часто меняется, возможности объектно-ориентированного программирования становятся очень полезными, поскольку изменения в коде программы можно легко вносить с минимальными предварительными знаниями о программе. Шаблон моста полезен , когда и класс, и то, что он делает, часто меняются. Сам класс можно рассматривать как абстракцию , а то, что класс может делать, как реализацию . Шаблон моста также можно рассматривать как два уровня абстракции.
Когда существует только одна фиксированная реализация, этот шаблон в мире C++ известен как идиома Pimpl .
Шаблон моста часто путают с шаблоном адаптера , и он часто реализуется с использованием шаблона адаптера объекта , например, в коде Java ниже.
Вариант: Реализацию можно разделить еще больше, отложив наличие реализации до момента использования абстракции.
Шаблон проектирования Bridge — один из двадцати трех известных шаблонов проектирования GoF , описывающих, как решать повторяющиеся проблемы проектирования для разработки гибкого и повторно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые проще внедрять, изменять, тестировать и повторно использовать. [1]
Какие проблемы может решить шаблон проектирования Bridge? [2]
При использовании подклассов разные подклассы реализуют абстрактный класс по-разному. Но реализация привязана к абстракции во время компиляции и не может быть изменена во время выполнения.
Какое решение описывает шаблон проектирования «Мост»?
Abstraction
) от ее реализации ( Implementor
), поместив их в отдельные иерархии классов.Abstraction
с точки зрения (путем делегирования) объекта Implementor
.Это позволяет настроить Abstraction
с Implementor
объектом во время выполнения.
См. также класс Unified Modeling Language и диаграмму последовательности ниже.
В приведенной выше диаграмме классов Unified Modeling Language абстракция ( Abstraction
) не реализована, как обычно, в одной иерархии наследования. Вместо этого существует одна иерархия для абстракции ( Abstraction
) и отдельная иерархия для ее реализации ( Implementor
), что делает их независимыми друг от друга. Abstraction
Интерфейс ( operation()
) реализован в терминах (путем делегирования) Implementor
интерфейса ( imp.operationImp()
). Диаграмма последовательности
UML показывает
взаимодействия во время выполнения: Объект делегирует реализацию объекту (путем вызова ) , который выполняет операцию и возвращается в .Abstraction1
Implementor1
operationImp()
Implementor1
Abstraction1
Шаблон Bridge объединяет объекты в древовидную структуру. Он отделяет абстракцию от реализации. Здесь абстракция представляет клиента, из которого будут вызываться объекты. Ниже приведен пример, реализованный на языке C#
// Помогает обеспечить действительно развязанную архитектуру public interface IBridge { void Function1 (); void Function2 (); } public class Bridge1 : IBridge { public void Function1 () { Console.WriteLine ( "Bridge1.Function1 " ) ; } public void Function2 () { Console.WriteLine ( "Bridge1.Function2 " ) ; } } public class Bridge2 : IBridge { public void Function1 () { Console.WriteLine ( "Bridge2.Function1 " ) ; } public void Function2 () { Console.WriteLine ( "Bridge2.Function2 " ) ; } } открытый интерфейс IAbstractBridge { void CallMethod1 (); void CallMethod2 (); } открытый класс AbstractBridge : IAbstractBridge { открытый мост IBridge ; public AbstractBridge ( IBridge мост ) { этот . мост = мост ; } public void CallMethod1 ( ) { this.bridge.Function1 ( ) ; } public void CallMethod2 ( ) { this.bridge.Function2 ( ) ; } }
Классы Bridge — это Реализация, которая использует ту же интерфейсно-ориентированную архитектуру для создания объектов. С другой стороны, абстракция берет экземпляр класса реализации и запускает его метод. Таким образом, они полностью отделены друг от друга.
абстрактный класс DrawingAPI abstract def draw_circle ( x : Float64 , y : Float64 , radius : Float64 ) end класс DrawingAPI1 < DrawingAPI def draw_circle ( x : Float , y : Float , radius : Float ) "API1.circle at #{ x } : #{ y } - radius: #{ radius } " конец конец класс DrawingAPI2 < DrawingAPI def draw_circle ( x : Float64 , y : Float64 , radius : Float64 ) "API2.circle at #{ x } : #{ y } - radius: #{ radius } " конец конец абстрактный класс Shape защищенный геттер drawing_api : DrawingAPI def инициализация ( @drawing_api ) конец абстрактный def рисовать абстрактный def resize_by_percentage ( процент : Float64 ) конец класс CircleShape < Форма геттер x : Float64 геттер y : Float64 геттер радиус : Float64 def initialize ( @x , @y , @radius , drawing_api : DrawingAPI ) super ( drawing_api ) end def draw @drawing_api . draw_circle ( @x , @y , @radius ) конец def resize_by_percentage ( процент : Float64 ) @radius *= ( 1 + процент / 100 ) конец конец класс BridgePattern def self.test shapes = [ ] of Shape shapes << CircleShape.new ( 1.0 , 2.0 , 3.0 , DrawingAPI1.new ) shapes << CircleShape.new ( 5.0 , 7.0 , 11.0 , DrawingAPI2.new ) формы . каждый do | shape | shape . resize_by_percentage ( 2.5 ) помещает форму . draw конец конец конец BridgePattern . тест
Выход
API1.circle в 1.0:2.0 - радиус: 3.075API2.круг в 5.0:7.0 - радиус: 11.275
#include <iostream> #include <string> #include <vector> класс DrawingAPI { public : virtual ~ DrawingAPI () = default ; virtual std :: string DrawCircle ( float x , float y , float radius ) const = 0 ; }; class DrawingAPI01 : public DrawingAPI { public : std :: string DrawCircle ( float x , float y , float radius ) const override { return "API01.circle at " + std :: to_string ( x ) + ":" + std :: to_string ( y ) + " - radius: " + std :: to_string ( radius ); } }; class DrawingAPI02 : public DrawingAPI { public : std :: string DrawCircle ( float x , float y , float radius ) const override { return "API02.circle at " + std :: to_string ( x ) + ":" + std :: to_string ( y ) + " - radius: " + std :: to_string ( radius ); } }; класс Shape { public : Shape ( const DrawingAPI & drawing_api ) : drawing_api_ ( drawing_api ) {} virtual ~ Shape () = default ; virtual std :: string Draw () const = 0 ; virtual float ResizeByPercentage ( const float percent ) = 0 ; защищено : const API рисования & API_рисунка ; }; class CircleShape : public Shape { public : CircleShape ( float x , float y , float radius , const API рисования и API рисования ) : Форма ( api_рисования ), x_ ( x ), y_ ( y ), радиус_ ( радиус ) {} std :: string Draw ( ) const override { return drawing_api_.DrawCircle ( x_ , y_ , radius_ ) ; } float ResizeByPercentage ( const float percent ) override { return radius_ *= ( 1.0f + percent / 100.0f ); } private : float x_ , y_ , radius_ ; }; int main ( int argc , char ** argv ) { const DrawingAPI01 api1 {}; const DrawingAPI02 api2 {}; std :: vector < CircleShape > shapes { CircleShape { 1.0f , 2.0f , 3.0f , api1 }, CircleShape { 5.0f , 7.0f , 11.0f , api2 } }; для ( auto & shape : shapes ) { shape.ResizeByPercentage ( 2.5 ) ; std :: cout << shape.Draw ( ) << std :: endl ; } вернуть 0 ; }
Выход:
API01.circle в 1.000000:2.000000 - радиус: 3.075000API02.круг в точке 5.000000:7.000000 - радиус: 11.275000
Следующая программа Java определяет банковский счет, который отделяет операции по счету от регистрации этих операций.
// Logger имеет две реализации: info и warning @FunctionalInterface interface Logger { void log ( String message ); static Logger info () { return message -> System.out.println ( " info: " + message ) ; } static Logger warning ( ) { return message - > System.out.println ( " warning: " + message ) ; } } абстрактный класс AbstractAccount { private Logger logger = Logger.info ( ) ; public void setLogger ( Logger logger ) { this.logger = logger ; } // часть журналирования делегирована реализации Logger protected void opera ( String message , boolean result ) { logger.log ( message + " result " + result ) ; } } class SimpleAccount extends AbstractAccount { private int balance ; public SimpleAccount ( int balance ) { this.balance = balance ; } public boolean isBalanceLow ( ) { return balance < 50 ; } public void withdraw ( int amount ) { boolean shouldPerform = balance >= amount ; if ( shouldPerform ) { balance - = amount ; } opera ( "снять" + amount , shouldPerform ); } } public class BridgeDemo { public static void main ( String [] args ) { SimpleAccount account = new SimpleAccount ( 100 ); account.record ( 75 ) ; if ( account.isBalanceLow ( )) { // вы также можете изменить реализацию Logger во время выполнения account.setLogger ( Logger.warning ( ) ) ; } account.record ( 10 ) ; account.record ( 100 ) ; } }
Будет выведено:
информация: снять 75 результат верныйпредупреждение: снять 10 результат верныйпредупреждение: отозвать 100 результат ложный
интерфейс API рисования { function drawCircle ( $x , $y , $radius ); }класс DrawingAPI1 реализует DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API1.circle at $x : $y radius $radius . \n " ; } }класс DrawingAPI2 реализует DrawingAPI { public function drawCircle ( $x , $y , $radius ) { echo "API2.circle at $x : $y radius $radius . \n " ; } }абстрактный класс Shape { protected $drawingAPI ; публичная абстрактная функция draw (); публичная абстрактная функция resizeByPercentage ( $pct ); защищенная функция __construct ( API рисования $drawingAPI ) { $this -> API рисования = $drawingAPI ; } }класс CircleShape расширяет Shape { private $x ; private $y ; private $radius ; public function __construct ( $x , $y , $radius , API рисования $drawingAPI ) { parent :: __construct ( $drawingAPI ); $this -> x = $x ; $this -> y = $y ; $this -> radius = $radius ; } public function draw () { $this -> drawingAPI -> drawCircle ( $this -> x , $this -> y , $this -> radius ); } публичная функция resizeByPercentage ( $pct ) { $this -> radius *= $pct ; } }класс Tester { public static function main () { $shapes = array ( new CircleShape ( 1 , 3 , 7 , new DrawingAPI1 ()), new CircleShape ( 5 , 7 , 11 , new DrawingAPI2 ()), ); foreach ( $shapes as $shape ) { $shape -> resizeByPercentage ( 2.5 ); $shape -> draw (); } } }Тестер :: main ();
Выход:
API1.круг с радиусом 1:3 17,5API2.круг с радиусом 5:7 27,5
API рисования признаков { def drawCircle ( x : Double , y : Double , radius : Double ) } класс DrawingAPI1 расширяет DrawingAPI { def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #1 $ x $ y $ radius " ) } класс DrawingAPI2 расширяет DrawingAPI { def drawCircle ( x : Double , y : Double , radius : Double ) = println ( s"API #2 $ x $ y $ radius " ) } абстрактный класс Shape ( drawingAPI : DrawingAPI ) { def draw () def resizePercentage ( pct : Double ) } class CircleShape ( x : Double , y : Double , var radius : Double , drawingAPI : DrawingAPI ) extends Shape ( drawingAPI : DrawingAPI ) { def draw ( ) = drawingAPI.drawCircle ( x , y , радиус ) def resizePercentage ( pct : Double ) { радиус *= pct } } объект BridgePattern { def main ( args : Array [ String ]) { Seq ( new CircleShape ( 1 , 3 , 5 , new DrawingAPI1 ), new CircleShape ( 4 , 5 , 6 , new DrawingAPI2 ) ) foreach { x => x . resizePercentage ( 3 ) x . draw () } } }
""" Пример шаблона моста. """ from abc import ABCMeta , abstractmethodNOT_IMPLEMENTED = "Вам следует это реализовать."класс API рисования : __metaclass__ = ABCMeta @abstractmethod def draw_circle ( self , x , y , radius ): вызвать NotImplementedError ( NOT_IMPLEMENTED )класс DrawingAPI1 ( DrawingAPI ): def draw_circle ( self , x , y , radius ): return f "API1.circle at { x } : { y } - radius: { radius } "класс DrawingAPI2 ( DrawingAPI ): def draw_circle ( self , x , y , radius ): return f "API2.circle at { x } : { y } - radius: { radius } "класс DrawingAPI3 ( DrawingAPI ): def draw_circle ( self , x , y , radius ): return f "API3.circle at { x } : { y } - radius: { radius } " Форма класса : __metaclass__ = ABCMeta drawing_api = None def __init__ ( self , drawing_api ): self . drawing_api = drawing_api @abstractmethod def draw ( self ): вызвать NotImplementedError ( NOT_IMPLEMENTED ) @abstractmethod def resize_by_percentage ( self , percent ): вызвать NotImplementedError ( NOT_IMPLEMENTED )класс CircleShape ( Shape ) : def __init__ ( self , x , y , radius , drawing_api ) : self.x = x self.y = y self.radius = radius super ( CircleShape , self ) .__ init__ ( drawing_api ) def draw ( self ) : return self.drawing_api.draw_circle ( self.x , self.y , self.radius ) def resize_by_percentage ( self , percent ) : self.radius * = 1 + percent / 100 класс BridgePattern : @staticmethod def test (): shapes = [ CircleShape ( 1.0 , 2.0 , 3.0 , DrawingAPI1 ()), CircleShape ( 5.0 , 7.0 , 11.0 , DrawingAPI2 ()), CircleShape ( 5.0 , 4.0 , 12.0 , DrawingAPI3 ()), ] для фигуры в фигурах : shape.resize_by_percentage ( 2.5 ) print ( shape.draw ( ) ) BridgePattern . тест ()
{{cite book}}
: |work=
игнорируется ( помощь ) От: Джеймс В. Купер (2003). Шаблоны проектирования C#: Учебное пособие. Addison-Wesley . ISBN 0-201-84453-2.