Patrones de Diseño y JavaScript: Adapter

El pattern Adapter (también conocido como Wrapper) pertenece al grupo de los patrones estructurales, y su objectivo es envolver y adaptar la interfaz de un objeto al contexto en el cual se lo requiere.

Esta adaptación puede requerirse por una mera cuestión de incompatibilidad entre el cliente y el objetivo así como también para complementar su funcionalidad o simplemente agregar un nivel de indirección* en la relación en cuestión (aquí también podría considerarse el pattern Bridge).

 

All problems in computer science can be solved by another level of indirection

Butler Lampson

 

Supongamos que en nuestra aplicación utilizamos jQuery para realizar nuestras consultas ajax contra el servidor, pero nos encontramos con el problema de que no resuelve los problemas específicos que plantea la situación (caché, cantidad de servicios limitados, manejo estándar de excepciones, etc).

Una posible (y horrible) solución sería modificar el código de jQuery (ya sea físicamente o por monkey-patching), agregando las funcionalidades requeridas lo cual agrega más problematicas que soluciones (dispersión de lógica, incompatibiliad con futuras versiones de jQuery, etc).

Lo que propone este pattern en cambio, es sobrellevar la incompatibilida expresada mediante la implementación de un objeto intermedio.

Estructura de la aplicación del patrón Adapter al problema planteado

La implementación en código en este caso es bastante sencilla, siendo que primero se valida el request, luego el cache y finalmente se realiza un request normalizado:

/**
 * Adapter para requests normalizados
 *
 * @param {String} service
 * @param {Object} options
 * @return {void}
 */
MyApp.remote.service = function(service, options) {
	options = options || {};

	// Validamos el servicio
	if(MyApp.validation.service(service)) {
		throw new Error('Invalid service required: ' + service);
	}

	// Verificamos si existe en cache
	if(options.cache !== false && MyApp.cache.get(service)) {
		// Ejecutamos el callback
		(options.success || function() {}).call(options.context,
			MyApp.cache.get(service));
		return;
	}

	// La aplicacion entra en espera si asi se requiere
	if(options.showLoading) {
		MyApp.setLoadingOn();
	}

	// Finalmente realizamos la consulta
	$.post({
		cache: false,
		// Obtenemos la url del servicio
		url: MyApp.remote.url(service),
		// Completamos los parametros
		params: MyApp.remote.completeParams(options.params),
		success: function(xhr) {
			// Obtenemos la respuesta en el formato especifico del app
			var data = MyApp.remote.getJSON(xhr);

			// Almacenamos en cache
			MyApp.cache.set(service, data));

			// Ejecutamos el callback
			(options.success || function() {}).call(options.context, data);
		},
		// Registramos todos los errores
		error: function() {
			MyApp.log.error('Service: ' + service);
			// Ejecutamos el callback si existiese
			(options.error || function() {}).call(options.context, null);
		},
		complete: function() {
			if(options.showLoading) {
				MyApp.setLoadingOff();
			}
		}
	});
}

Luego, los casos de uso serían como el siguiente:

MyApp.remote.service('/feed/', {
    showLoading: true,
    success: function(data) {
        //
    }
});

A diferencia del pattern Proxy, el Adapter puede no respetar la interfaz del objeto original, pudiendo adoptar formas más convenientes (como es el caso del ejemplo).
Otro patrón similar es el Bridge, pero a diferencia del Adapter su única responsabilidad es crear una abstracción entre la interfaz y la implementación a fines de que las mismas puedan variar independientemente.

Leer más:

 


Shortlink: http://goo.gl/2Qaru




Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comment

You may use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>