Patrón adaptador

Patrón de diseño en programación informática

En ingeniería de software , el patrón adaptador es un patrón de diseño de software (también conocido como wrapper , un nombre alternativo compartido con el patrón decorador ) que permite que la interfaz de una clase existente se use 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 objeto de documento de un documento XML en una estructura de árbol que se puede mostrar.

Descripción general

El patrón de diseño adaptador [2] es uno de los veintitrés patrones de diseño conocidos del Grupo de los Cuatro 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 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 simplemente 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.
  • Trabajar adaptercon (reutilizar) clases que no tienen la interfaz requerida.

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

Los clientes no saben si trabajan con una targetclase directamente o a través de adapteruna clase que no tiene la targetinterfaz.

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

Definición

Un adaptador permite que dos interfaces incompatibles trabajen 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 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 utilizar un adaptador cuando el contenedor debe respetar una interfaz particular y debe admitir un comportamiento polimórfico . Alternativamente, un decorador permite agregar o alterar el comportamiento de una interfaz en tiempo de ejecución, y se utiliza una fachada cuando se desea una interfaz más sencilla o más fácil para un objeto subyacente. [4]

PatrónIntención
Adaptador o envoltorioConvierte una interfaz en otra para que coincida con lo que espera el cliente.
DecoradorAgrega dinámicamente responsabilidad a la interfaz al envolver el código original
DelegaciónApoyar la “composición por encima de la herencia”
FachadaProporciona una interfaz simplificada

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 UML anterior , la clase que requiere una interfaz no puede reutilizarla directamente porque su interfaz no se ajusta a la interfaz. En cambio, funciona a través de una clase que implementa la interfaz en términos de :clienttargetadapteetargetclientadaptertargetadaptee

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

Patrón de adaptador de objetos

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

El patrón adaptador de objetos expresado en UML
El patrón adaptador de objetos 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 habitual que la interfaz esperada se cree como una clase de interfaz pura, especialmente en lenguajes como Java (anterior a 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 adaptador de clase expresado en LePUS3

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

Motivación a partir de la solución en tiempo de compilación

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

clase B. setStringData ( claseA . getStringData ());

Sin embargo, supongamos que se debe modificar el formato de los datos de la cadena. Una solución en tiempo de compilación es utilizar la herencia:

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

y quizás crear el objeto "formateado" correctamente en tiempo de ejecución por medio del 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 { String público getStringData (); }      clase pública ClassAFormat1 implementa StringProvider { claseA privada claseA = nulo ;           public ClassAFormat1 ( ClassA final a ) { classA = a ; }         public String getStringData () { formato de retorno ( classA . getStringData ()); }       formato de cadena privada ( string final sourceValue ) { // Manipular la cadena de origen en un formato requerido // por el objeto que necesita los datos del objeto de origen return sourceValue . trim (); } }          
  2. Escriba una clase adaptadora que devuelva la implementación específica del proveedor:
    clase pública ClassAFormat1Adapter extiende Adapter { objeto público adapt ( objeto final anObject ) { devolver nuevo ClassAFormat1 (( ClassA ) anObject ); } }                
  3. Registre el adaptercon un registro global, para que adapterpueda buscarse en tiempo de ejecución:
    AdapterFactory . getInstance (). registerAdapter ( ClassA . class , ClassAFormat1Adapter . class , "formato1" );  
  4. En el código, cuando se desea transferir datos de ClassAa ClassB, escribir:
    Adaptador adaptador = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . class , StringProvider . class , "format1" ); StringProvider proveedor = ( StringProvider ) adaptador . adapt ( classA ); Cadena cadena = proveedor . getStringData (); classB . setStringData ( cadena );             

    o más concisamente:

    claseB .setStringData ( (( StringProvider ) AdapterFactory .getInstance ( ) .getAdapterFromTo ( ClaseA .class , StringProvider .class , " format1 " ) .adaptar ( claseA ) ) .getStringData ( ) ) ;       
  5. La ventaja es que si se desea transferir los datos en un segundo formato, entonces hay que buscar el adaptador/proveedor diferente:
    Adaptador adaptador = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . class , StringProvider . class , "format2" );      
  6. Y si se desea generar los datos ClassAcomo, por ejemplo, datos de imagen en :Class C
    Adaptador adaptador = AdapterFactory . getInstance () . getAdapterFromTo ( ClassA . class , ImageProvider . class , "format2" ); ImageProvider proveedor = ( ImageProvider ) adaptador . adapt ( classA ); classC . setImage ( proveedor . getImage ());          
  7. De esta manera, el uso de adaptadores y proveedores permite múltiples "vistas" de ClassBy ClassChacia 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 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 adaptada como parámetro. Este parámetro se pasará a un miembro de instancia de . Cuando se llama a clientMethod, tendrá acceso a la instancia adaptada que permite acceder a los datos requeridos del adaptado y realizar operaciones sobre esos datos que generan el resultado deseado.[ClassName]To[Interface]AdapterDAOToProviderAdapter[ClassName]To[Interface]Adapter

Java

interfaz  ILightningPhone { void recarga (); void useLightning (); }     interfaz  IMicroUsbPhone { void recarga (); void useMicroUsb (); }     la clase  Iphone implementa ILightningPhone { conector booleano privado ;       @Override public void useLightning () { conector = true ; System.out.println ( " Lightning conectado " ) ; }          @Override public void recharge () { if ( conector ) { System . println ( " Recarga iniciada " ) ; System . println ( " Recarga finalizada" ); } else { System . println ( " Conectar Lightning primero" ); } } }               clase  Android implementa IMicroUsbPhone { conector booleano privado ;       @Override public void useMicroUsb ( ) { conector = true ; System.out.println ( " MicroUsb conectado " ) ; }          @Override public void recharge () { if ( connector ) { System . println ( " Recarga iniciada" ) ; System . println ( "Recarga finalizada" ); } else { System . println ( "Conectar MicroUsb primero" ); } } } / * exponiendo la interfaz de destino mientras se envuelve el objeto de origen */ class LightningToMicroUsbAdapter implements IMicroUsbPhone { private final ILightningPhone lightningPhone ;                        público LightningToMicroUsbAdapter ( ILightningPhone lightningPhone ) { este .lightningPhone = lightningPhone ; }        @Override public void useMicroUsb ( ) { System.out.println ( " MicroUsb conectado " ) ; lightningPhone.useLightning () ; }        @Override public void recarga () { lightningPhone.recarga ( ) ; } }      clase pública AdapterDemo { static void rechargeMicroUsbPhone ( IMicroUsbPhone teléfono ) { teléfono.useMicroUsb ( ) ; teléfono.recharge ( ) ; }            static void recargaLightningPhone ( ILightningPhone teléfono ) { teléfono.useLightning ( ) ; teléfono.recarga ( ) ; }        público estático void principal ( String [] args ) { Android android = nuevo Android (); Iphone iPhone = nuevo Iphone ();                Sistema . out . println ( "Recargando android con MicroUsb" ); rechargeMicroUsbPhone ( android );  Sistema . out . println ( "Recargando iPhone con Lightning" ); rechargeLightningPhone ( iPhone );  Sistema . out . println ( "Recargando iPhone con MicroUsb" ); rechargeMicroUsbPhone ( new LightningToMicroUsbAdapter ( iPhone )); } }    

Producción

Recargar android con MicroUsbMicroUSB conectadoRecarga comenzadaRecarga terminadaCómo recargar el iPhone con LightningRayo conectadoRecarga comenzadaRecarga terminadaRecargar iPhone con MicroUSBMicroUSB conectadoRayo conectadoRecarga comenzadaRecarga terminada

Pitón

""" Ejemplo de patrón adaptador. """ from  abc  import  ABCMeta ,  abstractmethodNOT_IMPLEMENTED  =  "Deberías implementar esto."RECARGA  =  [ "Recarga iniciada." ,  "Recarga finalizada." ]ADAPTADORES DE ALIMENTACIÓN  =  { "Android" :  "MicroUSB" ,  "iPhone" :  "Lightning" }CONECTADO  =  " {} conectado." CONNECT_FIRST  =  "Conectar {} primero."clase  RechargeTemplate ( metaclase = ABCMeta ): @abstractmethod  def  recarga ( self ):  genera  NotImplementedError ( NO_IMPLEMENTADO )clase  FormatIPhone ( RechargeTemplate ):  @abstractmethod  def  use_lightning ( self ):  generar  NotImplementedError ( NO_IMPLEMENTADO )clase  FormatAndroid ( RechargeTemplate ):  @abstractmethod  def  use_micro_usb ( self ):  generar  NotImplementedError ( NO_IMPLEMENTADO )clase  IPhone ( FormatIPhone ):  __name__  =  "iPhone" def  __init __ ( self )  : self.conector = Falso   def  use_lightning ( self ) :  self.conector = True print ( CONECTADO.formato ( ADAPTADORES_DE_ALIMENTACIÓN [ self .__ nombre__ ] ) )    def  recarga ( self ) :  if  self.conector : for estado in RECARGA : print ( estado ) else : print ( CONECTAR_PRIMERO.formato ( ADAPTADORES_DE_ALIMENTACIÓN [ self .__ nombre__ ] ) )       clase  Android ( FormatAndroid ):  __name__  =  "Android" def  __init __ ( self )  : self.conector = Falso   def  use_micro_usb ( self ) :  self.conector = True print ( CONECTADO.formato ( ADAPTADORES_DE_ALIMENTACIÓN [ self .__ nombre__ ] ) )    def  recarga ( self ) :  if  self.conector : for estado in RECARGA : print ( estado ) else : print ( CONECTAR_PRIMERO.formato ( ADAPTADORES_DE_ALIMENTACIÓN [ self .__ nombre__ ] ) )       clase  IPhoneAdapter ( FormatAndroid ):  def  __init __ ( self ,  mobile )  : self.mobile = mobile   def  recarga ( self ) :  self.mobile.recharge ( ) def  use_micro_usb ( self ) :  print ( CONECTADO.format ( ADAPTADORES_DE_ALIMENTACIÓN [ " Android " ] ) ) self.mobile.use_lightning ( ) clase  AndroidRecharger :  def  __init __ ( self )  : self.phone = Android ( ) self.phone.use_micro_usb ( ) self.phone.recharge ( )    clase  IPhoneMicroUSBRecharger :  def  __init__ ( self ):  self . phone  =  IPhone ()  self . phone_adapter  =  IPhoneAdapter ( self . phone )  self . phone_adapter . use_micro_usb ()  self . phone_adapter . recargar ()clase  IPhoneRecharger :  def  __init__ ( self ):  self . phone  =  IPhone ()  self . phone . use_lightning ()  self . phone . recarga ()print ( "Recargar Android con el cargador MicroUSB." ) AndroidRecharger () print ()print ( "Recargar iPhone con MicroUSB usando patrón de adaptador." ) IPhoneMicroUSBRecharger () print ()print ( "Recargar el iPhone con el cargador de iPhone." ) IPhoneRecharger ()

DO#

interfaz pública ILightningPhone { void ConnectLightning (); void Recharge (); }    Interfaz pública IUsbPhone { void ConnectUsb (); void Recarga (); }    clase pública sellada AndroidPhone : IUsbPhone { bool privado isConnected ; void público ConnectUsb ( ) { this.isConnected = true ; Console.WriteLine ( " Teléfono Android conectado. " ) ; }           public void Recharge () { if(this.isConnected ) { Console.WriteLine ( " Recargando el teléfono Android . " ); } else { Console.WriteLine ( " Primero conecte el cable USB. " ) ; } } }   clase pública sellada ApplePhone : ILightningPhone { bool privado isConnected ; void público ConnectLightning ( ) { this.isConnected = true ; Console.WriteLine ( " Teléfono Apple conectado. " ) ; }           public void Recharge () { if ( this.isConnected ) { Console.WriteLine ( " Recarga del teléfono Apple." ); } else { Console.WriteLine ( " Primero conecte el cable Lightning." ) ; } } }   clase pública sellada LightningToUsbAdapter : IUsbPhone { privada de solo lectura ILightningPhone lightningPhone ; bool privado isConnected ; público LightningToUsbAdapter ( ILightningPhone lightningPhone ) { this.lightningPhone = lightningPhone ; } público void ConnectUsb ( ) { this.lightningPhone.ConnectLightning ( ) ; }                public void Recarga ( ) { this.lightningPhone.Recarga ( ) ; } }  public void Main () { ILightningPhone applePhone = new ApplePhone ( ); IUsbPhone cable_adaptador = new LightningToUsbAdapter ( applePhone ) ; cable_adaptador.ConnectUsb ( ) ; cable_adaptador.Recharge (); }          

Producción:

Teléfono Apple conectado. Cable adaptador conectado. Teléfono Apple recargándose.


Véase también

Referencias

  1. ^ ab Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy ; Bates, Bert (2004). Patrones de diseño Head First. O'Reilly Media . pág. 244. ISBN 978-0-596-00712-6. OCLC  809772256. Archivado desde el original (libro de bolsillo) 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 . pp. 139ff. ISBN. 0-201-63361-2.
  3. ^ "El patrón de diseño Adapter - Problema, solución y aplicabilidad". w3sDesign.com . Archivado desde el original el 28 de agosto de 2017. Consultado el 12 de agosto de 2017 .
  4. ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Patrones de diseño Head First (libro de bolsillo) . Vol. 1. O'Reilly Media . Págs. 243, 252, 258, 260. ISBN. 978-0-596-00712-6. Recuperado el 2 de julio de 2012 .
  5. ^ "El patrón de diseño Adapter - Estructura y colaboración". w3sDesign.com . Archivado desde el original el 28 de agosto de 2017. Consultado el 12 de agosto de 2017 .
Obtenido de "https://es.wikipedia.org/w/index.php?title=Patrón_adaptador&oldid=1235788258"