jueves, 26 de abril de 2012

El patrón Javascript Proxy y los contextos paralelos


Introducción

Continuamos viendo patrones de diseño. Hemos analizado por el momento los dos más conocidos: elpatrón módulo y el módulo revelado. Toca ahora el turno de un recién llegado, el intraducible This Namespace Proxy.
Creado por el desarrollador inglés James Edwards, este patrón utiliza los comandos apply call para crear dos capas en las que contexto y argumentos se separan. Resulta, de lejos, el diseño más elegante visto hasta ahora:

El código

var myApp = {};
(function(){
  // Private variables / properties
  var foo = 'Hello';
  var bar = 'World';
 
  //Private method
  var myMessage = function(){
    return foo + ' ' + bar;
  };
 
  // Public Method
  this.sum = function( param1, param2 ){
    return param1 + param2;
  };
 
}).apply( myApp );
 
console.log( myApp.sum( 10, 5 ) ); // 15
console.log( myApp.myMessage() ); // Error, myApp.myMessage is not a function
La diferencia de este patrón con respecto a los anteriores está en la propia función que lo envuelve: en lugar de un autoejecutable a secas, estamos añadiendo los métodos al objeto principal mediante el comando apply.
En este contexto, this referencia siempre al padre (el objeto al que estamos extendiendo) lo que permite una flexibilidad extrema. La distinción entre métodos públicos y privados se realiza ahora mediante dicha referencia.
Una primera ventaja del uso de this, es que, al no tratarse de variables, estamos protegiendo el nombre de los métodos públicos de reasignaciones accidentales que puedan darse más adelante.
Pero además de añadir una capa de seguridad, este patrón permite avanzar en cuanto a escalabilidad de una arquitectura Javascript.

Módulos en paralelo

This Namespaces Proxy es brillante por su simplicidad conseguida gracias a un correcto uso del lenguaje: no hay artificios ni malabarismos como los que hemos visto anteriormente con el métodoreturn.
Tomándolo como punto de partida, podemos continuar jugando con el API apply y call para obtener un modelo capaz de ser asignado a dos, o más, contextos diferentes permitiéndo una ejecución en paralelo. Esta funcionalidad resulta extremadamente útil en aplicaciones complejas donde varios procesos participan de los mismos algoritmos sin interferir entre ellos. Un ejemplo básico de esta estructura sería:
// Contexts
var context1 = {}, context2 = {};
 
// Method for any context
var incrementNumber = function( param1 ){
  var startNumber = param1 || 0;
  this.increment = function(){
    return startNumber++;
  }
};
 
incrementNumber.call( context1 );
incrementNumber.call( context2, 10 );
 
console.log( context1.increment() ); // 0
console.log( context1.increment() ); // 1
console.log( context1.increment() ); // 2
console.log( context2.increment() ); // 10
console.log( context2.increment() ); // 11
console.log( context2.increment() ); // 12
Analizando el código anterior, vemos que partimos de dos contextos diferentes; en este caso, objetos vacíos. El método común que queremos aplicar se define más adelante y luego se asocia a los contextos anteriores mediante un call. El resultado son dos objetos independientes participando del mismo método.
Esta flexibilidad permite, por ejemplo, extender un único entorno consevando la herencia del método común que pasa a estar disponible mediante la referencia this:
context1.incrementTwice = function(){
  // First
  this.increment();
  // Second and go
  return this.increment();
};
 
console.log( context1.incrementTwice() ); // 1
El ejemplo anterior, aunque poco útil, muestra cómo se puede extender un contexto (objeto) de forma individual conservando la funcionalidad de los métodos comunes.

Exprimiendo el contexto

Angus Croll considera ir más allá: propone tomar una librería completa, contenerla dentro de un nuevo objeto y usar apply para asociarla al contexto que escojamos.
//library code
var protoQueryMooJo = function() {
    //everything
}
 
//user code
var thirdParty = {};
protoQueryMooJo.apply(thirdParty);
Esto permitiría por ejemplo, usar jQuery únicamente dentro de un contexto del código y Mootools en otro. Esto abre un amplio abanico de posibilidades en cuanto al ensamblaje de librerías propias o de terceros.

Conclusión

El This Namespace Proxy supone un cambio importante en cuanto al planteamiento de los patrones de diseño más tradicionales. El uso de fórmulas básicas del propio lenguaje como son la APIs call y applypermiten asociar métodos a un número ilimitados de contextos – objetos permitiendo una ejecución en paralelo de los mismos.
Llendo más allá, puede utilizarse esta estructura para conseguir que partes de un código (librerías enteras u otros métodos) actúen dentro de un determinado ámbito sin interferir con el resto disminuyendo drásticamente los riesgos de colisiones e incompatibilidades.

No hay comentarios:

Publicar un comentario