Adaptador

RECU-0181 (Recurso Patrón)

Descripción

Este patrón convierte la interfaz de una clase en otra interfaz para adaptarla a las necesidades de un desarrollo concreto. El patrón Adaptador permite que clases con interfaces incompatibles puedan trabajar juntas.

Nombre

También conocido como Wrapper (envoltorio)

Clasificación

Patrón estructural

Motivación

Es muy frecuente la necesidad de adaptadores para elementos de la vidad cotidiana: cargadores de baterías, tipos de enchufe, etc. Si traspasamos esta visión al mundo del software, en algunas ocasiones un conjunto de clases no es reutilizable simplemente por la interfaz que no concuerda con el dominio específico que una aplicación requiere. Es necesario crear un patrón que facilite esta reutilización y que permita no modificar la estructura de códigos del cliente y del servicio.

Aplicabilidad

  • Si se quiere reutilizar una clase pero su interfaz no concuerda con nuestras necesidades.
  • Cuando se desea crear una clase reutilizable que coopera con clases no relacionadas, es decir, clases que no tienen necesariamente interfaces compatibles.
  • Cuando se quiera utilizar un componente de caja negra.

Estructura

Una clase adaptadora hereda de la clase o clases que desea adaptar, ofreciendo una interfaz diferente a la clase o clases padre.

Un objeto adaptador es un objeto que contiene uno o varios objetos de la clase o clases que se desean adaptar. El interfaz del objeto adaptador será el requerido, e internamente se realizarán las operaciones de conversión necesarias para adaptar las peticiones a la interfaz del objeto y objetos adaptados.

Participantes

  • Objetivo define la interfaz específica del dominio que Cliente usa.
  • Cliente colabora con la conformación de objetos para la interfaz Objetivo.
  • Inicial define una interfaz o clase existente que necesita adaptarse
  • Adaptador adapta la interfaz de Inicial a la interfaz Objetivo

Colaboraciones

La clase Cliente llama a las operaciones sobre una instancia Adaptador. Posteriormente, el Adaptador llama a las operaciones de Inicial que llevan a cabo el pedido.

Consecuencias

El empleo de adaptadores de clase o de adaptadores de objeto tienen diferentes consecuencias:

Un adaptador de clase:

  • Adapta Inicial Objetivo desarrollando una clase Adaptador concreta. Como consecuencia, una clase adaptadora no funcionará cuando se desea adaptar una clase y todas sus subclases.
  • Permite a los Adaptadores sobrescribir algo de comportamiento de Inicial, ya que Adaptador es una subclase de Inicial.

Un adaptador de objeto:

  • Permite que un único Adaptador trabaje con muchos interfaces Iniciales, es decir, el Adaptador por sí mismo y las subclases (si es que la tiene). El Adaptador también puede agregar funcionalidad a todos los Iniciales de una sola vez.
  • Hace difícil sobrescribir el comportamiento de Inicial. Esto requerirá derivar Inicial y hacer que Adaptador se refiera a la subclase en lugar que al Inicial por sí mismo.

Implementación

Aquí hay otras cuestiones a considerar cuando se utiliza el patrón Adaptador:

  • ¿Qué nivel de adaptación debe hace el Adaptador? La cantidad de trabajo que el Adaptador debe realizar para adaptar la interfaz Inicial a la intefaz Objetivo puede varias. Hay un espectro de trabajo posible que puede ir desde una simple conversión (por ejemplo, cambiando los nombres de las operaciones) hasta el soporte de un conjunto de operaciones enteramente diferentes. La cantidad de trabajo que el Adaptador hace dependerá de la similitud existente entre la interfaz Inicial y la interfaz Objetivo.
  • Adaptadores Pluggables Una clase es más reutilizable cuando se minimiza la suposición que otras clases deben hacer para utilizarla. Mediante la construcción en una clase de adaptación de una interfaz, se elimina la suposición de que otras clases ven la misma interfaz. Dicho de otra manera, la adaptación de la interfaz nos permite incorporar nuestra clase en sistemas existentes que pueden esperar diferentes interfaces para la clase.

Para realizar una implementación correcta del patrón se recomienda:

Crear una nueva clase que será el Adaptador, que extienda del componente existente e implemente la interfaz obligatoria. De este modo tenemos la funcionalidad que queríamos y cumplimos la condición de implementar la interfaz

Código de ejemplo

class ClavijaCuadrada {
   private double anchura ;
   public ClavijaCuadrada( double w )       { anchura = w; }
   public double getAnchura()           { return anchura ; }
   public void   setAnchura( double w ) { anchura = w; }
}
class AgujeroRedondo {
   private int radio;
   public AgujeroRedondo( int r ) {
      radio = r;
      System.out.println( "AgujeroRedondo: max ClavijaCuadrada es " + r * Math.sqrt(2) );
   }
   public int getRadio() { return radio; }
}
class ClavijaCuadradaAdaptador{
  
   private ClavijaCuadrada sp;
   public ClavijaCuadradaAdaptador( double w ) { sp = new ClavijaCuadrada( w ); }
   // Identificar la interfaz deseada
   public void hacerApto( AgujeroRedondo rh ) {
      double cantidad = sp.getAnchura() - rh.getRadio() * Math.sqrt(2);
      System.out.println( "reduciendo ClavijaCuadrada " + sp.getAnchura() + " en " + ((cantidad< 0) ? 0 : cantidad) + " cantidad" );
      if (cantidad > 0) {
         sp.setAnchura( sp.getAnchura() - cantidad );
         System.out.println( "   Anchura es ahora " + sp.getAnchura() );
      }
   }
}
class AdaptadorDemoClavijaCuadrada{
   public static void main( String[] args ) {
      AgujeroRedondo     rh = new AgujeroRedondo( 5 );
      ClavijaCuadradaAdaptador spa;
      for (int i=6; i < 10; i++) {
         spa = new ClavijaCuadradaAdaptador( (double) i );
         spa.hacerApto( rh );
      }
   }
}

Usos conocidos

Un ejemplo dentro del JDK:

  • Para gestionar eventos un objeto debe de implementar EventListener
  • Para gestionar eventos de tipo Window debe de implementar la interfaz WindowListener que extiende deEventListener
  • WindowListener proporciona siete métodos pero en muchas ocasiones no se usan mas de tres, ¿es posible evitar la definición de clases derivadas de WindowListener que no añaden comportamiento para la mayoría de los métodos? JDK proporciona la clase WindowAdapter para tal fin

Patrones relacionados

  • El patrón de diseño Proxy define un representante para un objeto pero no cambia su interfaz.
  • El patrón de diseño Decorador amplia la funcionalidad de un objeto sin modificar su interfaz.

Contenidos relacionados

Recursos
Área: Desarrollo » Patrones de Diseño
Código Título Tipo Carácter
RECU-0013 Patrones de diseño Ficha Recomendado
RECU-0200 Proxy Patrón Recomendado
RECU-0186 Decorador Patrón Recomendado