Adaptador (patrón de diseño)

La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la versión revisada el 9 de marzo de 2016; las comprobaciones requieren 47 ediciones .
Adaptador
Adaptador

Adaptador de vista de estructura de plantilla
Tipo de estructural
Objetivo para organizar el uso de las funciones de un objeto que no está disponible para su modificación a través de una interfaz especialmente creada (lleva la interfaz de una clase (o varias clases) a la interfaz del tipo requerido)
Se aplica en casos el sistema admite los datos y el comportamiento necesarios, pero tiene una interfaz inapropiada. El uso más común del patrón Adapter es cuando desea crear una clase que se deriva de una clase abstracta recién definida o ya existente.
ventajas
  • encapsulación de la implementación de clases externas (componentes, bibliotecas), el sistema se vuelve independiente de la interfaz de clases externas;
  • la transición al uso de otras clases externas no requiere volver a trabajar el sistema en sí, es suficiente implementar una clase Adapter.
Plantillas relacionadas Fachada , Decorador
Descrito en Patrones de diseño

Adapter ( ing.  Adapter ) es un patrón de diseño estructural diseñado para organizar el uso de las funciones de un objeto que no está disponible para su modificación a través de una interfaz especialmente creada . En otras palabras, es un patrón de diseño estructural que permite que objetos con interfaces incompatibles trabajen juntos.

Características principales

Reto

El sistema admite los datos y el comportamiento requeridos, pero tiene una interfaz inadecuada.

Solución

El adaptador proporciona la creación de una clase contenedora [1] con la interfaz requerida.

Miembros

Una clase Adapterasigna una interfaz de clase Adapteea una interfaz de clase Target(que es implementada por la clase Adapter). Esto permite que el objeto Clientuse el objeto Adaptee(a través del adaptador Adapter) como si fuera una instancia de la clase Target.

De esta forma Clientaccede a la interfaz Targetimplementada por la clase Adapterque redirige la llamada a Adaptee.

Consecuencias

El patrón Adapter permite que los objetos existentes se incluyan en nuevas estructuras de objetos, independientemente de las diferencias en sus interfaces.

Notas y comentarios

El patrón Adapter permite que el proceso de diseño ignore las posibles diferencias en las interfaces de las clases existentes. Si hay una clase que tiene los métodos y propiedades requeridos (al menos conceptualmente), entonces, si es necesario, siempre puede usar el patrón Adapter para llevar su interfaz a la forma deseada.

Cerca del Adaptador está el patrón Fachada , no siempre es posible distinguir uno del otro [2] .

Aplicar una plantilla

Un ejemplo típico del uso del patrón Adapter es la creación de clases que conducen a una sola interfaz de una función de lenguaje PHP que brinda acceso a varios DBMS [3] .

En la figura se muestra una solución a este problema utilizando la plantilla del Adaptador.

Implementación

Incluir una clase ya existente en otra clase. La interfaz de la clase adjunta se actualiza para cumplir con los nuevos requisitos y las llamadas a sus métodos se convierten en llamadas a los métodos de la clase incluida.


Pasos de implementación

  1. Asegúrese de tener dos clases con interfaces incompatibles:
    • servicio útil : una clase de utilidad que no puede cambiar (es un tercero u otro código depende de ello);
    • uno o más clientes : clases de aplicaciones existentes que son incompatibles con el servicio debido a una interfaz inconveniente o que no coincide.
  2. Describa la interfaz de cliente a través de la cual las clases de aplicación podrían usar la clase de servicio.
  3. Cree una clase de adaptador implementando esta interfaz.
  4. Coloque un campo en el adaptador que almacenará una referencia al objeto de servicio. Normalmente, este campo se rellena con el objeto pasado al constructor del adaptador. En el caso de una adaptación simple, este objeto se puede pasar como parámetro a los métodos del adaptador.
  5. Implemente todos los métodos de interfaz de cliente en el adaptador. El adaptador debe delegar la mayor parte del trabajo al servicio.
  6. La aplicación solo debe usar el adaptador a través de la interfaz del cliente. Esto facilitará el cambio y la adición de adaptadores en el futuro.


Rubí

Ejemplo en rubí módulo AdapterPattern # Permite que el cliente use Adaptees con interfaces incompatibles a través de adaptadores con interfaz Target # Adaptado clase Twitter def twit pone 'Twit fue publicado' end end # La publicación de definición de Facebook de la clase Adaptee pone ' La publicación de Facebook fue publicada' end end # Módulo de destino WebServiceInterface def send_message raise NotImplementedError end end # Clase de adaptador TwitterAdapter incluye WebServiceInterface def inicializar @webservice = Twitter . nuevo fin def enviar_mensaje @webservice . final del tuit final # Clase de adaptador FacebookAdapter incluye WebServiceInterface def inicializar @webservice = Facebook . nuevo fin def enviar_mensaje @webservice . poste final final # Clase de cliente Mensaje attr_accessor :webservice definitivamente enviar @webservice . enviar_mensaje fin fin def auto . ejecutar pone '=> Adaptador' mensaje = Mensaje . nuevo mensaje _ servicio web = TwitterAdapter . mensaje nuevo _ enviar mensaje _ servicio web = adaptador de Facebook . mensaje nuevo _ enviar pone '' fin fin Patrón de adaptador . correr

Java - herencia

Ejemplo de Java (a través de la herencia) // Jefe de interfaz pública de destino { public Object makeBreakfast (); objeto público hacerAlmuerzo (); public Object hacerCena (); } // Adaptado public class Plumber { public Object getScrewNut () { ... } public Object getPipe () { ... } public Object getGasket () { ... } } // Adaptador public class ChiefAdapter extends Plumber implements Chief { public Object makeBreakfast () { return getGasket (); } public Object makeLunch () { return getPipe (); } public Object hacerCena () { return getScrewNut (); } } // Cliente public class Client { public static void eat ( Object plato ) { ... } public static void main ( String [] args ) { Chief ch = new ChiefAdapter (); Objeto plato = ch . hacerDesayuno (); comer ( plato ); plato = cap . hacerAlmuerzo (); comer ( plato ); plato = cap . hacerCena (); comer ( plato ); llamarAmbulancia (); } }

Composición Java

Ejemplo de Java (a través de la composición) // Archivo Chief.java Jefe de interfaz pública { objeto publico prepararDesayuno (); public Object hacerCena (); objeto público hacerCena (); } // Archivo fontanero.java Plomero de clase pública { objeto público getPipe () { devuelve nuevo objeto (); } objeto público getKey () { devuelve nuevo objeto (); } objeto público getScrewDriver () { devuelve nuevo objeto (); } } // Archivo ChiefAdapter.java La clase pública ChiefAdapter implementa Chief { fontanero privado fontanero = fontanero nuevo (); @Override public Object makeBreakfast () { return fontanero . obtener clave (); } @Override public Object makeDinner () { return fontanero . obtenerDestornillador (); } @Override public Object makeSupper () { return fontanero . obtenerTubo (); } } // Archivo cliente.java Cliente de clase pública { public static void main ( String [] args ) { Chief chief = new ChiefAdapter (); Clave de objeto = cabeza . hacerCena (); } }

escala

ejemplo de escala adaptador de objeto de paquete { objeto campo de batalla { var protegido redTroops : Array [ Tropa ] = Array () var protegida blueTroops : Array [ Tropa ] = Array () def addTroop ( tropa : Tropa ) : Unidad = { if ( tropa . lado == "rojo" ) { redTroops :+= tropa } else if ( tropa . lado == "blue" ) { blueTroops :+= troop } else { lanzar una nueva excepción ( s"Lado no válido ${ tropa . lado } para la tropa ${ tropa . nombre } " ) } } def getClosestEnemyTroop ( side : String ): Troop = { if ( side == "red" ) { getTroop ( blueTroops ) } else { getTroop ( redTroops ) } } def privado getTroop ( tropas : Array [ Troop ]): Troop = { if ( tropas . longitud == 0 ) { throw new Exception ( "No hay tropas disponibles" ) } tropas ( 0 ) } } class Troop ( val side : String , val name : String , val closeWeapon : String , val distanceWeapon : String ) { def mover ( dirección : Cadena , distancia : Int ): Unidad = { println ( s "Tropa $ nombre mueve $ dirección en $ distancia yardas" ) } def ataque ( Tropa enemiga : Tropa , tipo de ataque : Cadena ) : Unidad = { val arma = tipo de ataque coincidencia { case "distancia" => distanciaArma case "cerrar" => cerrarArma case _ => lanzar una nueva excepción ( s"Tipo de ataque no válido $ tipo de ataque para tropa $ nombre " ) } println ( s"La tropa $ nombre ataca a la tropa enemiga ${ TropaEnemiga . nombre } con su ${ arma } s" ) } } rasgo LanceKnightTroopTrait { def moveForward ( distancia : Int ) : Unidad def ataque más cercano ( tipo de ataque : cadena ) : unidad } class LanceKnightTroop ( override val side : String , override val name : String , override val closeWeapon : String , override val distanceWeapon : String ) extends Troop ( side , name , closeWeapon , distanceWeapon ) with LanceKnightTroopTrait { override def moverAdelante ( distancia : Int ): Unidad = { mover ( "adelante" , distancia ) } override def attackClosest ( attackType : String ): Unidad = { attack ( Battlefield . getClosestEnemyTroop ( side ), attackType ) } } objeto AdapterTest extiende AbstractTest { override def run (): Unidad = { val troop = nueva Tropa ( "azul" , "Arqueros" , "espada" , "arco largo" ) val lanceKnightTroop = nueva LanceKnightTroop ( "roja" , "Lance Knights" , "pica " , ballesta ) campo de batalla addTroop ( tropa ) Campo de batalla . addTroop ( lanceKnightTroop ) println ( "Salida:" ) lanceKnightTroop . moverAdelante ( 300 ) lanceKnightTroop . ataque más cercano ( "cerrar" ) } } } // Salida: // La tropa Lance Knights avanza 300 yardas // La tropa Lance Knights ataca a las tropas enemigas Archers con sus picas

PHP5

Ejemplo en PHP 5 <?php class DesarrolladorIndependiente1 { public function calc ( $a , $b ) { return $a + $b ; } } class IndependentDeveloper2 { nombre de función pública es muy largo e incómodo ( $ a , $ b ) { return $ a + $ b ; } } interfaz IAdapter { función pública suma ( $a , $b ); } class ConcreteAdapter1 implementa IAdapter { protected $object ; public function __construct () { $this -> object = new IndependentDeveloper1 (); } public function sum ( $a , $b ) { return $this -> object -> calc ( $a , $b ); } } class ConcreteAdapter2 implementa IAdapter { protected $object ; public function __construct () { $this -> object = new IndependentDeveloper2 (); } public function sum ( $a , $b ) { return $this -> object -> nameIsMuyLongAndUncomfortable ( $a , $b ); } } //en un lugar creamos un adaptador concreto y luego usamos la interfaz $adapter1 = new ConcreteAdapter1 (); $adaptador2 = new ConcreteAdapter2 (); /** * En todas partes del código no usamos clases directamente, sino a través de la interfaz * esta función no importa qué clase usemos, ya que dependemos de la interfaz * * @param IAdapter $adapter */ function sum ( IAdapter $ adaptador ) { echo $ adaptador -> suma ( 2 , 2 ); } suma ( $adaptador1 ); suma ( $adaptador2 );

PHP5.4

Ejemplo en PHP 5.4 (Rasgo) <?php class SomeClass { public function someSum ( $a , $b ) { return $a + $b ; } } class OtraClase { public function otraSuma ( $a , $b ) { return $a + $b ; } } trait TAdaptee { public function sum ( int $a , int $b ) { $método = $this -> method ; devuelve $esto -> $método ( $a , $b ); } } class SomeAdaptee extiende SomeClass { use TAdaptee ; método privado $ = 'someSum' ; } class AnotherAdaptee extiende AnotherClass { use TAdaptee ; método privado $ = 'otraSuma' ; } $alguna = new SomeAdaptee ; $otro = nuevo OtroAdaptado ; $algunos -> suma ( 2 , 2 ); $otro -> suma ( 5 , 2 );

PHP5.4 Compacto

Ejemplo en PHP 5.4 (Compacto) <?php trait TAdaptee { public function sum ( int $a , int $b ) { $método = $this -> method ; devuelve $esto -> $método ( $a , $b ); } } clase SomeClass { use TAdaptee ; método privado $ = 'someSum' ; public function someSuma ( $a , $b ) { return $a + $b ; } } class Otra Clase { use TAdaptee ; método privado $ = 'otraSuma' ; public function otraSuma ( $a , $b ) { return $a + $b ; } } $alguna = new AlgunaClase ; $otra = new OtraClase ; $algunos -> suma ( 2 , 2 ); $otro -> suma ( 5 , 2 );

JavaScript

ejemplo de JavaScript función Buscar ( texto , palabra ) { var texto = texto ; var palabra = palabra ; esto _ searchWordInText = función () { texto de retorno ; }; esto _ getWord = function () { return word ; }; }; function SearchAdapter ( adaptado ) { this . searchWordInText = función () { devuelve 'Estas palabras' + adaptado . getWord () + 'encontrado en el texto' + adaptado . buscarPalabraEnTexto (); }; }; var buscar = nueva búsqueda ( "texto" , "palabras" ); var searchAdapter = new SearchAdapter ( búsqueda ); Adaptador de búsqueda . buscarPalabraEnTexto ();

Pitón

Ejemplo en Python class GameConsole : def create_game_picture ( self ): devuelve 'imagen de la consola' antena de clase : def create_wave_picture ( self ): devuelve 'imagen de onda' class SourceGameConsole ( GameConsole ): def get_picture ( self ): return self . crear_imagen_del_juego () class SourceAntenna ( Antena ): def get_picture ( self ): return self . crear_imagen_onda () clase TV : def __init__ ( auto , fuente ): auto . source = source def show_picture ( self ): return self . fuente _ obtener_imagen () g = SourceGameConsole () a = SourceAntenna () game_tv = TV ( g ) cabel_tv = TV ( a ) print ( game_tv . show_picture ()) print ( cabel_tv . show_picture ())

C# - composición

Ejemplo de C# (Composición) utilizando el sistema ; adaptador de espacio de nombres { class MainApp { static void Main () { // Crear adaptador y colocar una solicitud Target target = new Adapter (); objetivo _ solicitud (); // Esperar a la Consola del usuario . leer (); } } // "Objetivo" class Target { Solicitud de vacío virtual público () { Consola . WriteLine ( "Llamado TargetRequest ()" ); } } // "Adaptador" Adaptador de clase : Target { Adaptee privado Adaptee = new Adaptee (); public override void Request () { // Posiblemente haga algún otro trabajo // y luego llame a SpecificRequest adaptee . Solicitud específica (); } } // "Adaptado" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Solicitud Específica Llamada()" ); } } }

C# - herencia

Ejemplo de C# (herencia) utilizando el sistema ; adaptador de espacio de nombres { class MainApp { static void Main () { // Crear adaptador y colocar una solicitud Adaptador adaptador = nuevo Adaptador (); adaptador _ solicitud (); // Esperar a la Consola del usuario . leer (); } } // "Objetivo" interfaz ITarget { Public void Solicitud (); } // Puedes usar la clase abstracta // "Adaptador" class Adapter : Adaptee , ITarget { public void Request () { // Posiblemente haga algún otro trabajo // y luego llame a SpecificRequest SpecificRequest (); } } // "Adaptado" class Adaptee { public void SpecificRequest () { Console . WriteLine ( "Solicitud Específica Llamada()" ); } } }

Delfos

ejemplo de Delfos adaptador de programa; {$CONSOLA DE TIPO DE APLICACIÓN} {$R *.res} usos Sistema.SysUtils; (*Interfaz de uso del cliente de la clase TTarget realizada como TAdapter*) (*TAdapter redirige la llamada a TAdaptee*) escribe TTarget = clase solicitud de función: cadena; virtual; final; TAdapte = clase función Solicitud específica: cadena; final; TAdapter = clase (TTarget) fAdaptado: TAdaptado; solicitud de función: cadena; anular; constructorCrear; final; { Objetivo } función TTarget.Solicitud: cadena; empezar Resultado: = 'Solicitud de destino llamada ()'; final; {Adaptado} función TAdaptee.SpecificRequest: cadena; empezar Resultado:= 'Solicitud Específica Llamada()'; final; {Adaptador} constructor TAdapter.Crear; empezar fAdaptee:= TAdaptee.Crear; final; función TAdapter.Solicitud: cadena; empezar (*Posiblemente haga algún otro trabajo y cuando llame a SpecificRequest*) Resultado:= fAdaptee.SpecificRequest; final; var objetivo: TTarget; empezar probar { TODO -oUser -cConsole Main : Insertar código aquí } (*crear adaptador y realizar una solicitud*) destino:= TAdapter.Crear; WriteLn(objetivo.Solicitud); WriteLn(#13#10+'Presione cualquier tecla para continuar...'); LeerLn; objetivo.Gratis; excepto en E: Excepción hacer Writeln(E.NombreClase, ': ', E.Mensaje); final; final.

Notas

  1. La proximidad de los significados de los términos shell y wrapper ( envoltura en inglés  - utilizado como sinónimo de decorador) a veces genera confusión y el Adaptador se define como sinónimo de la plantilla Decorador , mientras que estas son dos plantillas diferentes y la última resuelve una tarea diferente, a saber: conectar obligaciones adicionales al objeto.
  2. La diferencia es que el patrón Fachada está diseñado para simplificar la interfaz, mientras que el patrón Adaptador está diseñado para llevar varias interfaces existentes al mismo aspecto deseado.
  3. En versiones obsoletas del lenguaje PHP, el acceso al DBMS se implementa como un conjunto de funciones, para cada DBMS tienen nombres diferentes y, a veces, se utiliza un conjunto diferente de parámetros, lo que genera problemas importantes al cambiar de un DBMS a otro, si dicha transición no se proporciona de antemano utilizando la plantilla del adaptador.

Literatura

  • Alan Shalloway, James R. Trott. Patrones de diseño. Un nuevo enfoque del diseño orientado a objetos = explicación de los patrones de diseño: una nueva perspectiva del diseño orientado a objetos. - M .: "Williams" , 2002. - S. 288. - ISBN 0-201-71594-5 .
  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Técnicas de diseño orientado a objetos. Patrones de Diseño = Patrones de Diseño: Elementos de Software Reutilizable Orientado a Objetos. - San Petersburgo. : "Pedro" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (también ISBN 5-272-00355-1 )
  • Eric Freeman, Elizabeth Freeman. Patrones de diseño = Patrones de diseño Head First. - San Petersburgo. : Pedro, 2011. - 656 p. - ISBN 978-5-459-00435-9 .

Enlaces