Мостовой узор

Шаблон проектирования, используемый в программной инженерии

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

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

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

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

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

Обзор

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

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

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

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

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

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

Это позволяет настроить Abstractionс Implementorобъектом во время выполнения.
См. также класс Unified Modeling Language и диаграмму последовательности ниже.

Структура

Диаграмма классов и последовательностей UML

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

В приведенной выше диаграмме классов Unified Modeling Language абстракция ( Abstraction) не реализована, как обычно, в одной иерархии наследования. Вместо этого существует одна иерархия для абстракции ( Abstraction) и отдельная иерархия для ее реализации ( Implementor), что делает их независимыми друг от друга. AbstractionИнтерфейс ( operation()) реализован в терминах (путем делегирования) Implementorинтерфейса ( imp.operationImp()). Диаграмма последовательности
UML показывает взаимодействия во время выполнения: Объект делегирует реализацию объекту (путем вызова ) , который выполняет операцию и возвращается в .Abstraction1Implementor1operationImp()Implementor1Abstraction1

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

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

Пример

С#

Шаблон 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 результат ложный

PHP

интерфейс  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 . тест ()

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

Ссылки

  1. ^ ab Gamma, Erich ; Helm, Richard ; Johnson, Ralph ; Vlissides, John (1994). Шаблоны проектирования: элементы повторно используемого объектно-ориентированного программного обеспечения . Addison-Wesley. стр. 151. ISBN 0-201-63361-2.
  2. ^ "Шаблон проектирования моста - проблема, решение и применимость". w3sDesign.com . Получено 2017-08-12 .
  3. ^ "Шаблон проектирования моста - Структура и сотрудничество". w3sDesign.com . Получено 2017-08-12 .
  • Мост в UML и в LePUS3 (формальный язык моделирования)
  • Шаблоны проектирования C#: Шаблон «Мост». 2002-12-20. {{cite book}}: |work=игнорируется ( помощь ) От: Джеймс В. Купер (2003). Шаблоны проектирования C#: Учебное пособие. Addison-Wesley . ISBN 0-201-84453-2.
Взято с "https://en.wikipedia.org/w/index.php?title=Bridge_pattern&oldid=1183383676"