Patrón de adaptador


De Wikipedia, la enciclopedia libre
  (Redirigido desde el patrón del adaptador )
Saltar a navegación Saltar a búsqueda

En ingeniería de software , el patrón de adaptador es un patrón de diseño de software (también conocido como envoltorio , un nombre alternativo compartido con el patrón de decorador ) que permite que la interfaz de una clase existente se utilice como otra interfaz. [1] A menudo se utiliza para hacer que las clases existentes funcionen con otras sin modificar su código fuente .

Un ejemplo es un adaptador que convierte la interfaz de un modelo de objetos de documento de un documento XML en una estructura de árbol que se puede mostrar.

Visión general

El patrón de diseño del adaptador [2] es uno de los veintitrés patrones de diseño conocidos de Gang of Four 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.

El patrón de diseño del adaptador resuelve problemas como: [3]

  • ¿Cómo se puede reutilizar una clase que no tiene una interfaz que requiere un cliente?
  • ¿Cómo pueden trabajar juntas las clases que tienen interfaces incompatibles?
  • ¿Cómo se puede proporcionar una interfaz alternativa para una clase?

A menudo, una clase (ya existente) no se puede reutilizar solo porque su interfaz no se ajusta a la interfaz que requieren los clientes.

El patrón de diseño del adaptador describe cómo resolver estos problemas:

  • Defina una adapterclase separada que convierta la interfaz (incompatible) de una clase ( adaptee) en otra interfaz ( target) que requieran los clientes.
  • Trabaje a través de una adapterpara trabajar con (reutilizar) clases que no tienen la interfaz requerida.

La idea clave en este patrón es trabajar a través de un separado adapterque adapte la interfaz de una clase (ya existente) sin cambiarla.

Los clientes no saben si trabajan con una targetclase directamente o mediante adapteruna clase que no tiene la targetinterfaz.

Consulte también el diagrama de clases de UML a continuación.

Definición

Un adaptador permite que dos interfaces incompatibles funcionen juntas. Esta es la definición real de un adaptador. Las interfaces pueden ser incompatibles, pero la funcionalidad interna debe adaptarse a la necesidad. El patrón de diseño del adaptador permite que las clases que de otro modo serían incompatibles trabajen juntas al convertir la interfaz de una clase en una interfaz esperada por los clientes.

Uso

Se puede usar un adaptador cuando el contenedor debe respetar una interfaz particular y debe admitir un comportamiento polimórfico . Alternativamente, un decorador hace posible agregar o alterar el comportamiento de una interfaz en tiempo de ejecución, y se usa una fachada cuando se desea una interfaz más fácil o más simple para un objeto subyacente. [4]

Estructura

Diagrama de clases UML

Un diagrama de clases UML de muestra para el patrón de diseño del adaptador. [5]

En el diagrama de clases de UML anterior , la clientclase que requiere una targetinterfaz no puede reutilizar la adapteeclase directamente porque su interfaz no se ajusta a la targetinterfaz. En cambio, clientfunciona a través de una adapterclase que implementa la targetinterfaz en términos de adaptee:

  • La object adapterforma implementa la targetinterfaz delegando a un adapteeobjeto en tiempo de ejecución ( adaptee.specificOperation()).
  • La class adapterforma en que implementa la targetinterfaz heredando de una adapteeclase en tiempo de compilación ( specificOperation()).

Patrón de adaptador de objeto

En este patrón de adaptador, el adaptador contiene una instancia de la clase que envuelve. En esta situación, el adaptador realiza llamadas a la instancia del objeto empaquetado .

El patrón de adaptador de objeto expresado en UML
El patrón de adaptador de objeto expresado en LePUS3

Patrón de adaptador de clase

Este patrón de adaptador utiliza múltiples interfaces polimórficas que implementan o heredan tanto la interfaz esperada como la interfaz preexistente. Es típico que la interfaz esperada se cree como una clase de interfaz pura , especialmente en lenguajes como Java (antes de JDK 1.8) que no admiten la herencia múltiple de clases. [1]

El patrón de adaptador de clase expresado en UML .
El patrón de adaptador de clase expresado en LePUS3

Otra forma de patrón de adaptador de tiempo de ejecución

Motivación de la solución de tiempo de compilación

Se desea classAsuministrar classBalgunos datos, supongamos algunos Stringdatos. Una solución de tiempo de compilación es:

claseB . setStringData ( classA . getStringData ());

Sin embargo, suponga que se debe variar el formato de los datos de la cadena. Una solución de tiempo de compilación es usar la herencia:

La  clase  pública Format1ClassA  extiende  ClassA  {  @Override  public  String  getStringData ()  {  formato de retorno  ( toString ()); } } 

y quizás crear el objeto de "formateo" correcto en tiempo de ejecución mediante el patrón de fábrica .

Solución de adaptador en tiempo de ejecución

Una solución que utiliza "adaptadores" procede de la siguiente manera:

  1. Defina una interfaz de "proveedor" intermediario y escriba una implementación de esa interfaz de proveedor que envuelva la fuente de los datos, ClassAen este ejemplo, y genere los datos formateados según corresponda:
     Interfaz  pública StringProvider  {  public  String  getStringData (); }La  clase  pública ClassAFormat1  implementa  StringProvider  {  privada  ClassA  classA  =  null ; public  ClassAFormat1 ( final  ClassA  a )  {  classA  =  a ;  } public  String  getStringData ()  {  formato de retorno  ( classA . getStringData ()); }  private  String  format ( final  String  sourceValue )  {  // Manipular la cadena fuente en un formato requerido  // por el objeto que necesita el  retorno de  datos del objeto fuente sourceValue . recortar ();  } }
  2. Escriba una clase de adaptador que devuelva la implementación específica del proveedor:
    La  clase  pública ClassAFormat1Adapter  extiende el  adaptador  {  public  Object  adapt ( objeto final  anObject ) { return new ClassAFormat1 (( ClassA ) anObject ); } }       
  3. Registre el adaptercon un registro global, de modo que adapterse pueda buscar en tiempo de ejecución:
    AdapterFactory . getInstance (). registerAdapter ( ClassA . clase ,  ClassAFormat1Adapter . clase ,  "formato1" );
  4. En el código, cuando desee transferir datos de ClassAa ClassB, escriba:
    Adaptador  adaptador  =  AdapterFactory . getInstance ()  . getAdapterFromTo ( ClassA . clase ,  StringProvider . clase ,  "formato1" ); Proveedor StringProvider  = adaptador ( StringProvider ) . adaptar ( classA ); String string = proveedor . getStringData (); claseB . setStringData ( cadena );      

    o más concisamente:

    claseB . setStringData (  (( StringProvider )  AdapterFactory . getInstance ()  . getAdapterFromTo ( ClassA . clase ,  StringProvider . clase ,  "formato1" )  . adapt ( classA ))  . getStringData ());
  5. La ventaja se puede ver en que, si se desea transferir los datos en un segundo formato, busque el adaptador / proveedor diferente:
    Adaptador  adaptador  =  AdapterFactory . getInstance ()  . getAdapterFromTo ( ClassA . clase ,  StringProvider . clase ,  "formato2" );
  6. Y si se desea generar los datos ClassAcomo, digamos, datos de imagen en :Class C
    Adaptador  adaptador  =  AdapterFactory . getInstance ()  . getAdapterFromTo ( ClassA . clase ,  ImageProvider . clase ,  "formato2" ); Proveedor de ImageProvider  = adaptador ( ImageProvider ) . adaptar ( classA ); classC . setImage ( proveedor . getImage ());   
  7. De esta manera, el uso de los adaptadores y los proveedores permite múltiples "vistas" por ClassBy ClassCen ClassAsin tener que alterar la jerarquía de clases. En general, permite un mecanismo para flujos de datos arbitrarios entre objetos que se pueden adaptar a una jerarquía de objetos existente.

Implementación del patrón adaptador

Al implementar el patrón del adaptador, para mayor claridad, se puede aplicar el nombre de la clase a la implementación del proveedor; por ejemplo ,. Debe tener un método constructor con una variable de clase adaptable como parámetro. Este parámetro se pasará a un miembro de instancia de . Cuando se llama al clientMethod, tendrá acceso a la instancia adaptee que permite acceder a los datos requeridos del adaptee y realizar operaciones en esos datos que generan la salida deseada.[ClassName]To[Interface]AdapterDAOToProviderAdapter[ClassName]To[Interface]Adapter

Java

interfaz  LightningPhone  {  void  recharge ();  void  useLightning (); }interfaz  MicroUsbPhone  {  recarga vacía  (); void useMicroUsb (); }  la clase  Iphone  implementa  LightningPhone  {  conector booleano privado  ;  @Override  public  void  useLightning ()  {  conector  =  verdadero ;  Sistema . fuera . println ( "Rayo conectado" );  } @Override  public  void  recharge ()  {  if  ( conector )  {  System . fuera . println ( "Recarga iniciada" );  Sistema . fuera . println ( "Recarga finalizada" );  }  else  {  System . fuera . println ( "Conectar Lightning primero" );  }  } }clase  Android  implementa  MicroUsbPhone  {  conector booleano privado  ;  @Override  public  void  useMicroUsb ()  {  conector  =  verdadero ;  Sistema . fuera . println ( "MicroUsb conectado" );  } @Override  public  void  recharge ()  {  if  ( conector )  {  System . fuera . println ( "Recarga iniciada" );  Sistema . fuera . println ( "Recarga finalizada" );  }  else  {  System . fuera . println ( "Conectar MicroUsb primero" );  }  } } / * exponiendo la interfaz de destino mientras envuelve el objeto de origen * / class  LightningToMicroUsbAdapter implementa  MicroUsbPhone  {  LightningPhone final privado  lightningPhone ;   public  LightningToMicroUsbAdapter ( LightningPhone  lightningPhone )  {  this . lightningPhone  =  lightningPhone ;  } @Override  public  void  useMicroUsb ()  {  System . fuera . println ( "MicroUsb conectado" );  lightningPhone . useLightning ();  } @Override  public  void  recharge ()  {  lightningPhone . recargar ();  } }público  de clase  AdapterDemo  {  static  void  rechargeMicroUsbPhone ( MicroUsbPhone  teléfono )  {  teléfono . useMicroUsb ();  teléfono . recargar ();  } static  void  rechargeLightningPhone ( teléfono LightningPhone  ) { teléfono . useLightning (); teléfono . recargar (); }     public  static  void  main ( String []  args )  {  Android  android  =  new  Android ();  Iphone  iPhone  =  nuevo  Iphone (); Sistema . fuera . println ( "Recarga de Android con MicroUsb" );  rechargeMicroUsbPhone ( android ); Sistema . fuera . println ( " Recargar iPhone con Lightning" );  rechargeLightningPhone ( iPhone ); Sistema . fuera . println ( "Recarga de iPhone con MicroUsb" );  rechargeMicroUsbPhone ( nuevo  LightningToMicroUsbAdapter  ( iPhone ));  } }

Producción

Recarga de Android con MicroUsb
MicroUsb conectado
Recarga iniciada
Recarga finalizada
Recargar iPhone con Lightning
Rayo conectado
Recarga iniciada
Recarga finalizada
Recarga de iPhone con MicroUsb
MicroUsb conectado
Rayo conectado
Recarga iniciada
Recarga finalizada

Pitón

"" " Ejemplo de patrón de adaptador. " "" De  abc  import  ABCMeta ,  método abstractoNOT_IMPLEMENTED  =  "Debería implementar esto".RECARGA  =  [ "Recarga iniciada". ,  "Recarga finalizada". ]POWER_ADAPTERS  =  { "Android" :  "MicroUSB" ,  "iPhone" :  "Lightning" }CONECTADO  =  " {} conectado". CONNECT_FIRST  =  "Conectar {} primero".class  RechargeTemplate :  __metaclass__  =  ABCMeta @abstractmethod  def  recharge ( self ):  levanta  NotImplementedError ( NOT_IMPLEMENTED )class  FormatIPhone ( RechargeTemplate ):  @abstractmethod  def  use_lightning ( self ):  raise  NotImplementedError ( NOT_IMPLEMENTED )class  FormatAndroid ( RechargeTemplate ):  @abstractmethod  def  use_micro_usb ( self ):  raise  NotImplementedError ( NOT_IMPLEMENTED )clase  IPhone ( FormatIPhone ):  __name__  =  "iPhone" def  __init__ ( self ):  self . conector  =  Falso def  use_lightning ( self ):  self . conector  =  Impresión verdadera  ( formato CONNECTED . ( POWER_ADAPTERS [ self . __name__ ])) def  recharge ( self ):  if  self . conector :  para el  estado  en  RECARGA :  imprimir ( estado )  más :  imprimir ( CONNECT_FIRST . formato ( POWER_ADAPTERS [ self . __name__ ]))clase  Android ( FormatAndroid ):  __name__  =  "Android" def  __init__ ( self ):  self . conector  =  Falso def  use_micro_usb ( self ):  self . conector  =  Impresión verdadera  ( formato CONNECTED . ( POWER_ADAPTERS [ self . __name__ ])) def  recharge ( self ):  if  self . conector :  para el  estado  en  RECARGA :  imprimir ( estado )  más :  imprimir ( CONNECT_FIRST . formato ( POWER_ADAPTERS [ self . __name__ ]))class  IPhoneAdapter ( FormatAndroid ):  def  __init__ ( self ,  mobile ):  self . mobile  =  móvil def  recharge ( self ):  self . móvil . recargar () def  use_micro_usb ( self ):  print ( CONNECTED . format ( POWER_ADAPTERS [ "Android" ]))  self . móvil . use_lightning ()clase  AndroidRecharger :  def  __init__ ( self ):  self . teléfono  =  Android ()  self . teléfono . use_micro_usb ()  self . teléfono . recargar ()clase  IPhoneMicroUSBRecharger :  def  __init__ ( self ):  self . teléfono  =  IPhone ()  self . phone_adapter  =  IPhoneAdapter ( auto . teléfono )  self . phone_adapter . use_micro_usb ()  self . phone_adapter . recargar ()class  IPhoneRecharger :  def  __init__ ( self ):  self . teléfono  =  IPhone ()  self . teléfono . use_lightning ()  self . teléfono . recargar ()print ( "Recarga de Android con el cargador MicroUSB." ) AndroidRecharger () print ()print ( "Recarga del iPhone con MicroUSB usando un patrón de adaptador." ) IPhoneMicroUSBRecharger () print ()print ( "Recarga de iPhone con cargador de iPhone" ) IPhoneRecharger ()

C#

pública  interfaz  ILightningPhone { nula  ConnectLightning (); Recarga vacía  (); } interfaz  pública IUsbPhone { void  ConnectUsb (); Recarga vacía  (); } AndroidPhone de clase sellada  pública : IUsbPhone { bool privado está conectado ;     public  void  ConnectUsb () { esto . isConnected  =  true ; Consola . WriteLine ( "teléfono Android conectado" ); }public  void  Recharge () { if  ( this . isConnected ) { Console . WriteLine ( "recarga del teléfono Android" ); } else { Consola . WriteLine ( "Conecte primero el cable USB" ); } } } ApplePhone de clase pública sellada  : ILightningPhone { bool privado está conectado ;     public  void  ConnectLightning () { esto . isConnected  =  true ; Consola . WriteLine ( "teléfono Apple conectado" ); }public  void  Recharge () { if  ( this . isConnected ) { Console . WriteLine ( "recarga del teléfono Apple" ); } else { Consola . WriteLine ( "Conecte primero el cable Lightning" ); } } }pública  sellada  clase  LightningToUsbAdapter  :  IUsbPhone { privado  de sólo lectura  ILightningPhone  lightningPhone ;private  bool  isConnected ;public  LightningToUsbAdapter ( ILightningPhone  lightningPhone ) { this . lightningPhone  =  lightningPhone ; esto . lightningPhone . ConnectLightning (); }public  void  ConnectUsb () { esto . isConnected  =  true ; Consola . WriteLine ( "Cable adaptador conectado" ); }public  void  Recharge () { if  ( this . isConnected ) { this . lightningPhone . Recarga (); } else { Consola . WriteLine ( "Conecte primero el cable USB" ); } } }public  void  Main () { ILightningPhone  applePhone  =  nuevo  ApplePhone (); IUsbPhone  adapterCable  =  nuevo  LightningToUsbAdapter ( applePhone ); adaptadorCable . ConnectUsb (); adaptadorCable . Recarga (); }

Producción:

Teléfono de Apple conectado.
Cable adaptador conectado.
Recarga del teléfono Apple.

Ver también

  • Adaptador de patrones de diseño de Java - Adaptador
  • Delegación , muy relevante para el patrón de adaptador de objeto.
  • Principio de inversión de dependencia , que se puede considerar como la aplicación del patrón de adaptador, cuando la clase de alto nivel define su propia interfaz (adaptadora) al módulo de bajo nivel (implementado por una clase de adaptado).
  • Arquitectura de puertos y adaptadores
  • Calce
  • Función de envoltura
  • Biblioteca de envoltorios

Referencias

  1. ^ a b Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy ; Bates, Bert (2004). Patrones de diseño de Head First . O'Reilly Media . pag. 244. ISBN 978-0-596-00712-6. OCLC  809772256 . Archivado desde el original ( tapa blanda ) el 4 de mayo de 2013 . Consultado el 30 de abril de 2013 .
  2. ^ Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison Wesley . págs.  139ff . ISBN 0-201-63361-2.
  3. ^ "El patrón de diseño del adaptador: problema, solución y aplicabilidad" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
  4. ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (rústica) . 1 . O'Reilly Media . págs. 243, 252, 258, 260. ISBN  978-0-596-00712-6. Consultado el 2 de julio de 2012 .
  5. ^ "El patrón de diseño del adaptador - estructura y colaboración" . w3sDesign.com . Consultado el 12 de agosto de 2017 .
Obtenido de " https://en.wikipedia.org/w/index.php?title=Adapter_pattern&oldid=1035956424 "