stringtranslate.com

Patrón de puente

El patrón puente es un patrón de diseño utilizado en ingeniería de software que pretende "desacoplar una abstracción de su implementación para que las dos puedan variar de forma independiente" , introducido por la Banda de los Cuatro . [1] El puente usa encapsulación , agregación y puede usar herencia para separar responsabilidades en diferentes clases .

Cuando una clase varía con frecuencia, las características de la programación orientada a objetos se vuelven muy útiles porque los cambios en el código de un programa se pueden realizar fácilmente con un conocimiento previo mínimo sobre el programa. El patrón puente es útil cuando tanto la clase como lo que hace varían con frecuencia. Se puede considerar la clase misma como la abstracción y lo que la clase puede hacer como la implementación . El patrón del puente también se puede considerar como dos capas de abstracción.

Cuando solo hay una implementación fija, este patrón se conoce como modismo Pimpl en el mundo C++ .

El patrón puente a menudo se confunde con el patrón adaptador y, a menudo, se implementa utilizando el patrón adaptador de objeto ; por ejemplo, en el código Java siguiente.

Variante: la implementación se puede desacoplar aún más difiriendo la presencia de la implementación hasta el punto en que se utiliza la abstracción.

Descripción general

El patrón de diseño Bridge es uno de los veintitrés patrones de diseño GoF bien conocidos que describen cómo resolver problemas de diseño recurrentes para diseñar software orientado a objetos flexible y reutilizable, es decir, objetos que son más fáciles de implementar, cambiar, probar y reutilizar. [1]

¿Qué problemas puede resolver el patrón de diseño Bridge? [2]

Cuando se utilizan subclases, diferentes subclases implementan una clase abstracta de diferentes maneras. Pero una implementación está vinculada a la abstracción en tiempo de compilación y no se puede cambiar en tiempo de ejecución.

¿Qué solución describe el patrón de diseño del Puente?

Esto permite configurar un Abstractioncon un Implementorobjeto en tiempo de ejecución.
Consulte también la clase del Lenguaje de modelado unificado y el diagrama de secuencia a continuación.

Estructura

Diagrama de secuencia y clase UML

Un ejemplo de diagrama de secuencia y clase UML para el patrón de diseño Bridge. [3]

En el diagrama de clases del Lenguaje de modelado unificado anterior , una abstracción ( Abstraction) no se implementa como es habitual en una única jerarquía de herencia. En cambio, hay una jerarquía para una abstracción ( Abstraction) y una jerarquía separada para su implementación ( Implementor), lo que las hace independientes entre sí. La Abstractioninterfaz ( operation()) se implementa en términos de (delegando a) la Implementorinterfaz ( imp.operationImp()).
El diagrama de secuencia UML muestra las interacciones en tiempo de ejecución: el objeto delega la implementación al objeto (llamando a ), que realiza la operación y regresa a .Abstraction1Implementor1operationImp()Implementor1Abstraction1

Diagrama de clase

Abstracción (clase abstracta)
define la interfaz abstracta
mantiene la referencia del Implementador.
Abstracción refinada (clase normal)
extiende la interfaz definida por Abstraction
Implementador (interfaz)
define la interfaz para las clases de implementación
ConcreteImplementor (clase normal)
implementa la interfaz del Implementador
Puente en LePUS3 (leyenda)

Ejemplo

C#

El patrón de puente compone objetos en estructura de árbol. Desacopla la abstracción de la implementación. Aquí la abstracción representa el cliente desde el cual se llamarán los objetos. A continuación se proporciona un ejemplo implementado en C#.

// Ayuda a proporcionar una arquitectura verdaderamente desacoplada public interface IBridge { void Function1 (); Función vacía2 (); }      clase pública Puente1 : IBridge { función pública vacía1 () { Consola . WriteLine ( "Puente1.Función1" ); }           public void Function2 () { Consola . WriteLine ( "Puente1.Función2" ); } }     clase pública Puente2 : IBridge { función pública vacía1 () { Consola . WriteLine ( "Puente2.Función1" ); }           public void Function2 () { Consola . WriteLine ( "Bridge2.Function2" ); } }     interfaz pública IAbstractBridge { void CallMethod1 (); void CallMethod2 (); }      clase pública AbstractBridge : IAbstractBridge { puente público IBridge ;        public AbstractBridge ( puente IBridge ) { este . puente = puente ; }        public void CallMethod1 () { esto . puente . Función1 (); }      public void CallMethod2 () { esto . puente . Función2 (); } }     

Las clases Bridge son la implementación que utiliza la misma arquitectura orientada a interfaz para crear objetos. Por otro lado, la abstracción toma una instancia de la clase de implementación y ejecuta su método. Por tanto, están completamente desacoplados unos de otros.

Cristal

clase abstracta DrawingAPI abstract def draw_circle ( x : Float64 , y : Float64 , radio : Float64 ) fin             clase DrawingAPI1 < DrawingAPI def draw_circle ( x : Float , y : Float , radio : Float ) "API1.circle en #{ x } : #{ y } - radio: #{ radio } " end end               clase DrawingAPI2 < DrawingAPI def draw_circle ( x : Float64 , y : Float64 , radio : Float64 ) "API2.circle en #{ x } : #{ y } - radio: #{ radio } " end end               clase abstracta Forma protegida getter draw_api : DrawingAPI        def inicializar ( @drawing_api ) finalizar   resumen def dibujar resumen def resize_by_percentage ( porcentaje : Float64 ) fin       clase CircleShape < Captador de forma x : Captador Float64 y : Captador Float64 radio : Float64                def inicializar ( @x , @y , @radius , dibujo_api : DrawingAPI ) super ( dibujo_api ) fin         def dibujar @drawing_api . draw_circle ( @x , @y , @radius ) fin      def resize_by_percentage ( porcentaje : Float64 ) @radius *= ( 1 + porcentaje / 100 ) fin fin         clase BridgePattern def self . formas de prueba = [] de formas de formas << CircleShape . nuevas ( 1.0 , 2.0 , 3.0 , DrawingAPI1 . new ) formas << CircleShape . nuevo ( 5.0 , 7.0 , 11.0 , DrawingAPI2 . nuevo )                     formas . cada uno hace | forma | forma . resize_by_percentage ( 2.5 ) pone forma . dibujar final final final       Patrón de puente . prueba

Producción

API1.circle en 1.0:2.0 - radio: 3.075API2.circle en 5.0:7.0 - radio: 11.275

C++

#include <iostream> #include <cadena> #include <vector>   clase DrawingAPI { público : virtual ~ DrawingAPI () = predeterminado ; virtual std :: cadena DrawCircle ( flotante x , flotante y , radio flotante ) const = 0 ; };                  clase DrawingAPI01 : public DrawingAPI { public : std :: string DrawCircle ( float x , float y , float radio ) const override { return "API01.circle at " + std :: to_string ( x ) + ":" + std :: to_string ( y ) + " - radio: " + std :: to_string ( radio ); } };                              clase DrawingAPI02 : public DrawingAPI { public : std :: string DrawCircle ( float x , float y , float radio ) const override { return "API02.circle at " + std :: to_string ( x ) + ":" + std :: to_string ( y ) + " - radio: " + std :: to_string ( radio ); } };                              clase Forma { público : Forma ( const DrawingAPI & dibujo_api ) : dibujo_api_ ( dibujo_api ) {} virtual ~ Forma () = predeterminado ;              virtual std :: cadena Draw () const = 0 ; flotante virtual ResizeByPercentage ( porcentaje flotante constante ) = 0 ;             protegido : const DrawingAPI & dibujo_api_ ; };   clase CircleShape : forma pública { público : CircleShape ( flotante x , flotante y , radio flotante , constante API de dibujo y API_dibujo ) : forma ( api_dibujo ), x_ ( x ), y_ ( y ), radio_ ( radio ) {}                      std :: cadena Draw () const override { return dibujo_api_ . DibujarCírculo ( x_ , y_ , radio_ ); }          float ResizeByPercentage ( porcentaje flotante constante ) anular { radio de retorno_ *= ( 1.0f + porcentaje / 100.0f ); } privado : flotante x_ , y_ , radio_ ; };                  int main ( int argc , char ** argv ) { const DrawingAPI01 api1 {}; const DibujoAPI02 api2 {}; std :: vector < CircleShape > formas { CircleShape { 1.0f , 2.0f , 3.0f , api1 }, CircleShape { 5.0f , 7.0f , 11.0f , api2 } };                         for ( auto & forma : formas ) { forma . Cambiar tamaño por porcentaje ( 2.5 ); std :: cout << forma . Dibujar () << std :: endl ; }            devolver 0 ; } 

Producción:

API01.circle en 1.000000:2.000000 - radio: 3.075000API02.circle en 5.000000:7.000000 - radio: 11.275000

Java

El siguiente programa Java define una cuenta bancaria que separa las operaciones de la cuenta del registro de estas operaciones.

// Logger tiene dos implementaciones: información y advertencia @FunctionalInterface interfaz  Logger { void log ( string message ); Información del registrador estático () { mensaje de retorno -> Sistema . afuera . println ( "informacion: " + mensaje ); } Advertencia de registrador estático () { mensaje de retorno -> Sistema . afuera . println ( "advertencia: " + mensaje ); } }                           clase abstracta AbstractAccount { logger privado logger = Logger . información (); public void setLogger ( Logger registrador ) { this . registrador = registrador ; } // la parte de registro se delega a la implementación del registrador protected void operar ( mensaje de cadena , resultado booleano ) { logger . iniciar sesión ( mensaje + "resultado" + resultado ); } }                                 clase  CuentaSimple extiende CuentaAbstracta { saldo int privado ; cuenta simple pública ( saldo int ) { this . saldo = equilibrio ; } public boolean isBalanceLow () { saldo de retorno < 50 ; } retiro nulo público ( monto int ) { booleano deberíaPerformar = saldo >= monto ; if ( debería realizar ) { saldo -= monto ; } operar ( "retirar" + monto , debería realizar ); } }                                                 clase pública BridgeDemo { public static void main ( String [] args ) { Cuenta SimpleAccount = nueva Cuenta Simple ( 100 ); cuenta . retirarse ( 75 ); if ( cuenta . isBalanceLow ()) { // también puede cambiar la implementación del registrador en tiempo de ejecución de la cuenta . setLogger ( Logger . advertencia ()); } cuenta . retirar ( 10 ); cuenta . retirar ( 100 ); } }                          

Dará salida:

información: retirar 75 resultados verdaderosadvertencia: retirar 10 resultados verdaderosadvertencia: retirar 100 resultados falsos

PHP

interfaz  DrawingAPI {  función  dibujarCircle ( $x ,  $y ,  $radius ); }clase  DrawingAPI1  implementa  DrawingAPI {  función pública  drawCircle ( $x , $y , $radius ) { echo "API1.circle en $x : $y radio $radius . \n " ; } }       clase  DrawingAPI2  implementa  DrawingAPI {  función pública  drawCircle ( $x , $y , $radius ) { echo "API2.circle en $x : $y radio $radius . \n " ; } }        clase  abstracta Forma {  protegida  $drawingAPI ;  sorteo de función abstracta  pública (); función abstracta pública resizeByPercentage ( $pct );       función  protegida __construct ( API de dibujo  $API de dibujo )  {  $this -> API de dibujo  =  $API de dibujo ;  } }class  CircleShape  extiende  Shape {  privado  $x ;  privado  $y ;  radio $ privado  ;  función  pública __construct ( $x ,  $y ,  $radius ,  DrawingAPI  $drawingAPI )  {  padre :: __construct ( $drawingAPI );  $esto -> x  =  $x ;  $esto -> y  =  $y ;  $esto -> radio  =  $radio ;  }  función  pública dibujar ()  {  $this -> dibujoAPI -> drawCircle ( $this -> x ,  $this -> y ,  $this -> radio );  }  función  pública resizeByPercentage ( $pct )  {  $this -> radio  *=  $pct ;  } }class  Tester {  public  static  function  main ()  {  $shapes  =  array (  nueva  CircleShape ( 1 ,  3 ,  7 ,  nueva  DrawingAPI1 ()),  nueva  CircleShape ( 5 ,  7 ,  11 ,  nueva  DrawingAPI2 ()),  ); foreach  ( $formas  como  $forma )  {  $forma -> resizeByPercentage ( 2.5 );  $forma -> dibujar ();  }  } }Probador :: principal ();

Producción:

API1.círculo con un radio de 1:3 17,5API2.círculo con un radio de 5:7 27,5

escala

rasgo DrawingAPI { def drawCircle ( x : Doble , y : Doble , radio : Doble ) }         clase DrawingAPI1 extiende DrawingAPI { def drawCircle ( x : Doble , y : Doble , radio : Doble ) = println ( s"API #1 $ x $ y $ radio " ) }               clase DrawingAPI2 extiende DrawingAPI { def drawCircle ( x : Doble , y : Doble , radio : Doble ) = println ( s"API #2 $ x $ y $ radio " ) }               clase abstracta Forma ( DrawingAPI : DrawingAPI ) { def draw () def resizePercentage ( pct : Double ) }         clase CircleShape ( x : Doble , y : Doble , var radio : Doble , dibujoAPI : DibujoAPI ) extiende Forma ( dibujoAPI : DibujoAPI ) {              def dibujar () = API de dibujo . dibujarCírculo ( x , y , radio )      def resizePercentage ( pct : Doble ) { radio *= pct } }       object BridgePattern { def main ( args : Array [ String ] ) { Seq ( nueva CircleShape ( 1 , 3 , 5 , nueva DrawingAPI1 ), nueva CircleShape ( 4 , 5 , 6 , nueva DrawingAPI2 ) ) foreach { x => x . cambiar tamañoPorcentaje ( 3 ) x . dibujar () } } }                           

Pitón

""" Ejemplo de patrón de puente. """ de  abc  import  ABCMeta ,  método abstractoNOT_IMPLEMENTED  =  "Deberías implementar esto."clase  DrawingAPI :  __metaclass__  =  ABCMeta @abstractmethod  def  draw_circle ( self ,  x ,  y ,  radio ):  levanta  NotImplementedError ( NOT_IMPLEMENTED )clase  DrawingAPI1 ( DrawingAPI ):  def  draw_circle ( self ,  x ,  y ,  radio ):  return  f "API1.circle en { x } : { y } - radio: { radio } "clase  DrawingAPI2 ( DrawingAPI ):  def  draw_circle ( self ,  x ,  y ,  radio ):  return  f "API2.circle en { x } : { y } - radio: { radio } "class  DrawingAPI3 ( DrawingAPI ):  def  draw_circle ( self ,  x ,  y ,  radio ):  return  f "API3.circle en { x } : { y } - radio: { radio } " Forma de clase :  __metaclass__  =  ABCMeta dibujo_api  =  Ninguno  def  __init__ ( self ,  dibujo_api ):  self . dibujo_api  =  dibujo_api @abstractmethod  def  dibujar ( self ):  generar  NotImplementedError ( NOT_IMPLEMENTED ) @abstractmethod  def  resize_by_percentage ( self ,  porcentaje ):  elevar  NotImplementedError ( NOT_IMPLEMENTED )clase  CircleShape ( Forma ):  def  __init__ ( self ,  x ,  y ,  radio ,  dibujo_api ):  self . x  =  x  uno mismo . y  =  y  yo . radio  =  radio  super ( CircleShape ,  self ) . __init__ ( dibujo_api ) def  dibujar ( self ):  devolver  self . dibujo_api . draw_circle ( self.x , self.y , self.radio )   def  resize_by_percentage ( self ,  porcentaje ):  self . radio  *=  1  +  por ciento  /  100clase  BridgePattern :  @staticmethod  def  test ():  formas  =  [  CircleShape ( 1.0 ,  2.0 ,  3.0 ,  DrawingAPI1 ()),  CircleShape ( 5.0 ,  7.0 ,  11.0 ,  DrawingAPI2 ()),  CircleShape ( 5.0 ,  4.0 ,  12.0 ,  DrawingAPI3 () ),  ] para  la forma  en  las formas :  forma . resize_by_percentage ( 2.5 )  imprimir ( forma . dibujar ())Patrón de puente . prueba ()

Ver también

Referencias

  1. ^ ab Gamma, Erich ; Timón, Richard; Johnson, Ralph ; Vlissides, John (1994). Patrones de diseño: elementos de software reutilizable orientado a objetos . Addison-Wesley. pag. 151.ISBN​ 0-201-63361-2.
  2. ^ "El patrón de diseño del puente: problema, solución y aplicabilidad". w3sDesign.com . Consultado el 12 de agosto de 2017 .
  3. ^ "El patrón de diseño del puente: estructura y colaboración". w3sDesign.com . Consultado el 12 de agosto de 2017 .

enlaces externos