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 |
Sí |
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
- 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.
- Describa la interfaz de cliente a través de la cual las clases de aplicación podrían usar la clase de servicio.
- Cree una clase de adaptador implementando esta interfaz.
- 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.
- Implemente todos los métodos de interfaz de cliente en el adaptador. El adaptador debe delegar la mayor parte del trabajo al servicio.
- 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
- ↑ 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.
- ↑ 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.
- ↑ 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