Patrón de Diseño: Adapter


Hola bienvenidos de nueva cuenta a su blog StudentPlace. ¿De que estaremos hablando hoy? Pues simple y sencillamente del patrón de diseño Adapter.

Una parte importante de cualquier sistema es poder ser adaptado y reutilizado según las necesidades que tengamos al momento de desarrollar software, es por ello que surge este tipo de patrón.

Este patrón "sirve para hacer que dos interfaces, en principio diferentes, puedan comunicarse." Pondré un ejemplo que me gusto, lo estoy tomando de otro sitio pero me servirá para explicar muy bien a lo que vamos.

Patrones de diseño: Adapter

Yo nunca he salido de mi país, pero si me he topado con las ganas de comprar productos extranjeros, de hecho mi teléfono lo compre desde el distribuidor en japón (aunque creo se producen en España), en fin, mi dilema al recibirlo fue que prácticamente el cargador original era de anclaje europeo y yo soy de américa, en resumen acabada la batería no podía recargarlo como tradicionalmente se hace.

Distintos tipos de clavijas que se usan a lo largo del mundo.

Para mi suerte mi regulador de corriente poseía una entrada adaptada para ambos tipos de contactos, pero de igual manera tenia que ir a mi tienda local de electrónica y conseguir un adaptador de corriente:

Adaptador de corriente Europeo/Americano

Cuál es el principio de todo esto, pues prácticamente tengo dos elementos incompatibles entre si (mi contacto y mi cargador) los cuales imposibilitan cargar mi batería debido a su estructura, es decir dos interfaces distintas, por lo cual necesito de un puente que las comunique, es decir, mi adaptador.

Bien, espero vaya entrando el hilo en la aguja, en fin, este patrón nos permitirá adaptar, modificar, en cierta forma las clases que nosotros tengamos que utilizar para poder utilizarlas y escribir el menor código posible acorde a nuestra necesidad, recordemos el principio DRY ("Don´t Repeat Yourself"), es decir, no hagamos mas cosas de las que necesitamos si ya las hicimos o ya están hechas.

Componentes del Patrón Adapter:



El patrón adapter está típicamente conformado bajo la siguiente estructura:

  • Client: Actor que interactúa con el Adapter. Básicamente la parte de código que invoca al clase necesaria.
  • Target: Interface que nos permitirá homogenizar la forma de trabajar con las interfaces incompatibles, esta interface es utilizada para crear los Adapter. En español, el adaptador.
  • Adapter: Representa la implementación del Target, el cual tiene la responsabilidad de mediar entre el Client y el Adaptee. Oculta la forma de comunicarse con el Adaptee. Traducido es la clase adaptada para funcionar con el adaptador.
  • Adaptee: Representa la clase con interface incompatible.
Si uso la analogía de mi teléfono
  • El enchufe: o toma corriente es el cliente.
  • El adaptador de corriente: seria la clase adapter y target en conjunto.
  • Adaptee: mi cargador, el cuál necesita de ayuda para cargar mi teléfono.
Tipos de Adaptación:

Al ser un patrón estructural este se divide en patrones orientados a objetos y en patrones orientados a clases, veamos cada uno de ellos de forma rápida.

Patrón Adapter con clases:

Aquí se emplean interfaces para combinar clases incompatibles. Bueno, lo regular es emplear interfaces, también es posible con clases abstractas. Este tipo es menos utilizada por que utiliza herencia múltiple. Crearemos una clase adaptador que herede de la clase o clases a adaptar, cuyos métodos pueden ser sobreescritos. Además el adaptador deberá implementar la nueva interfaz que deseamos utilizar. La adaptación se realiza llamando a los métodos del padre. No permite la adaptación de las subclases de la clase adaptada.

Veamos un ejemplo:

Yo tengo en lo personal el dilema que en mi escuela la mayoría de los proyectores tiene solamente conexión VGA, por lo tanto mi computadora no puede ser usada de forma normal para emitir vídeo, es por ello que tuve que conseguir un adaptador HDMI - VGA:

Resultado de imagen para adaptador hdmi a vga


Este tipo de adaptador convierte la señal digital en señales analógicas separando el audio y vídeo en 2 salidas distintas. Si deseamos hacer una simulación en java tendríamos lo siguiente:

Clase client:


Esta clase lo único que contiene es la llamada a los métodos necesarios para la transmisión de vídeo "desde mi computadora", como observamos al conectar el cable HDMI no necesito ningún tipo de adaptador, puede ser una conexión directa, sin embargo para conectar un cable VGA o incluso RCA necesito un adaptador.

Clase target:


Esta clase lo único que contiene son lo métodos que necesitamos sobrescribir de la clase a adaptar.

Clase adapter:


Esta es la clase que necesitamos adaptar, dado que realmente es lo mismo, lo que vamos a emitir son datos audiovisuales recibidos desde el mismo puerto, sin embargo cada tipo de cable, en este caso, necesita transformar la señal de manera distinta, por lo tanto el método TransmitirDatosAudioVisuales() deberá ser reescrito para acoplar las necesidades de cada cable.

Clases Adaptee:

Para cables RCA:


Para VGA:


Como podemos observar en ambas clases, tanto la clase CableRCA como CableVGA incorporan métodos distintos y diferentes en la practica, sin embargo, nosotros por cuestiones técnicas necesitamos que sus objetos funcionen al ser llamados por el mismo método y "hagan lo mismo" sin importar que sean diferentes.

Es así que el método TransmitirDatosAudioVisuales() de ambas clases adaptadas llaman sus otros métodos internos los cuales se encargan de:

  • Procesar el vídeo
  • Procesar el audio
  • Y emitirlo por cable para que llegue al equipo final.
Y como resultado tenemos: 



Patrón Adapter con Objetos:

En este tipo de método creamos una clase adaptadora que contiene una instancia de la clase o clases a adaptar. Para compatibilizar las clases, el adaptador hace llamadas a la instancia del objeto u objetos a adaptar. Este adaptador funciona con la clase adaptada y todas sus subclases.

Pondré un claro ejemplo donde se debió haber usado, no sé si lo sepas, dejaré un articulo al respecto sobre ello en mis fuentes, en fin, hace años un satélite de la NASA destinado a monitorear el clima en marte desapareció, si, desapareció sin rastro aparente, ¿Razón? Algo estúpida pero sencilla, los cálculos que la computadora realizaba se hacían usando el sistema decimal de medida mientras que los técnicos le dieron información en el sistema anglosajón, durante mucho tiempo se preguntaron ¿Por qué rayos se salia de la trayectoria que debía seguir? lo que ellos no sabían era que entre mas trataban de corregirlo desde tierra lo iban empeorando más y más.

En fin, aquí se debió revisar el sistema del satélite y si no querían complicarse, debieron adaptar el sistema para funcionar con su sistema de medida.

Bueno, nosotros vamos a hacer algo similar como ejemplo de lo que ellos debieron haber hecho, es algo tan simple.

Digamos que tengo un auto autónomo, de esos que se conducen solos, el cual fue construido en E.U.A, en el cual el usuario puede indicarle al auto la velocidad a la que desea ir en el vehículo, sin embargo el auto reconoce la velocidad en formato de Millas por hora. El problema viene aquí, digamos que una empresa decide vender este mismo auto en México, en México la gente no sabe de MPH, todo aquí se maneja en Kilómetros por hora, y mi jefe, por decir algo, me pide que aparte de adaptar el idioma de la interfaz modifique la parte de la velocidad para que la persona indique en KPH que tan rápido desea ir.

Para iniciar, yo no estoy dispuesto a reescribir miles de lineas de código por que para empezar yo no se como funciona el auto a nivel de programación y bueno no es conveniente modificar el código que ya esta "perfectamente funcional", capaz y provoco algún error y me echan la culpa de miles de muertes, con esto aclaro que por alguna razón tengo acceso al código fuente del sistema, y yo para hacer lo que me pidieron haré esta magia.

Clase Client:

Pues como en el caso anterior, tomaremos a la clase client a aquella que contiene nuestro main, en este caso "la nueva interfaz en español que diseñaría":



Clase target:



En este caso la clase target incorporara de igual manera los métodos que yo necesito modificar e incorporar.

Clase adapter:



Aquí encontramos la clase a ser adaptada, es decir la que ofrece en este caso el fabricante, que como dijimos, realmente no nos conviene tocar, solo nos dedicaremos a mandarle los datos correctos a las funciones correctas para que realice lo que queremos.

Clase adapte:



Y finalmente la clase propia, aquí como observamos, lo único que hacemos es convertir la velocidad que deseé el usuario a la velocidad en millas por hora y pasarlo como parámetro al método velocity para que el haga el resto.

Es así que obtenemos el siguiente resultado:

Como vemos, yo como programador solo tuve que (en teoría) escribir como 20 lineas de código y el trabajo ya esta hecho, solo necesito hacer una conversión y mandar el dato al resto del sistema ya creado. Como vemos, la computadora del auto sigue procesando la información como si fueran MPH pero externamente sabemos que no es así.

En resumen:
Podemos decir que este patrón es muy útil a la hora de hacer compatibles clases distintas que no guardan relación entre si. Es muy útil al momento de utilizar clases externas en nuestros proyectos.
  • Ventajas: hace que dos interfaces incompatibles, sean compatibles. Puede servir para encapsular clases que no controlamos, y que pueden cambiar.
  • Desventajas: como muchos patrones, añade complejidad al diseño. Hay quién dice que este patrón es un parche, utilizado en malos diseños.
Bien, espero que esta entrada te haya sido útil, por favor ayúdame compartiendo en redes sociales y te agradezco por pasar a leer mi contenido, gracias.


Fuentes:

Comentarios

Publicar un comentario