Mostrando entradas con la etiqueta Patrones. Mostrar todas las entradas
Mostrando entradas con la etiqueta Patrones. Mostrar todas las entradas

domingo, 6 de diciembre de 2009

Patron Proxy en Flash

Recientemente me encontraba trabajando con Shared Objects (SO) en Flex para persistir ciertas propiedades en el cliente y empece a ver mas frecuentemente el uso de este codigo:


var settings:SharedObject = SharedObject().getLocal("/settings");

try
{
settings.data["property"] = value;
settings.flush();
}catch(e:Error)
{
...
}


Inmediatamente decidi mover esto dentro de una clase donde tenia un SharedObject y desde donde simplemente invocaba un metodo y le pasaba 2 parametros, uno con el key y otro con el value para el key, terminando con algo asi:


public function put(key:String, value:*):void
{
try
{
_sharedObject.data[key] = value;
_sharedObject.flush();
}
catch(e:Error)
{
log.error("Error while persisting setting. " + e);
}
}


Ya mi codigo empezo a verse con mucho menos lineas de codigo y tenia una clase reutilizable para interactuar con SO:

Definia esto al inicio de mi clase indicando cual shared object queria usar
var settings:SharedObjectWrapper = new SharedObjectWrapper(SharedObject().getLocal("/settings"));

Invocaba a mi clase asi:
settings.put("property", value);

Sin embargo, queria hacer algo todavia mas sencillo, mas que por funcionalidad por majaderia :) y me acorde de la clase Proxy que trae el Flash API.

Que es?

La clase Proxy que viene en el paquete flash.utils, es una clase "abstracta"(aunque no es verdad pues AS3 no permite esas clases), que quiere decir que sus metodos que usemos deben ser definidos a la hora de extender la clase y ademas no puede ser instanciada. Esta clase viene a reemplazar a Object.__resolve y Object.addPropert en AS2.

El Proxy nos permite agregar comportamiento a otras clases por medio de la definicion de ciertos metodos. Estos metodos se encargan de "escuchar" los llamados a las propiedades y servicios (funciones) en un objeto y responder a esos llamados para redireccionarlos dentro de la clase (como veremos mas abajo)

Algunos de los metodos principales definidos en la clase Proxy son:

callProperty(name:*, ... rest):*

Escucha el llamado de una funcion, los parametros son:
name -> nombre de la funcion
rest -> un Array de parametros

y retorna un valor de cualquier tipo

getProperty(name:*):*

Escucha el llamado a una propiedad de un objeto
name -> nombre de la propiedad
y retorna un valor de cualquier tipo

setProperty(name:*, value:*):void

Escucha el llamado a una propiedad de un objeto a la que se le quiera asignar un valor
name -> nombre de la propiedad
value -> valor a setear, de cualquier tipo

Que quiere decir?

Que extendiendo esta clase y algunos de los metodos definidos podemos hacer que nuestras clases que ya existan puedan tener un comportamiento adicional al que ya tenian, sobre todo si son clases hechas por otras personas o que no podamos modficar.
Vamos a ver un ejemplo, digamos que ocupamos tener un objeto dentro de nuestra clase en el cual guardaremos propiedades como un Hash. Esto lo podemos hacer facilmente haciendo esto:


var hash:Object = new Object();

hash['prop'] = value;

trace(hash.prop);


Sin embargo nuestros requerimientos nos indican que debemos logguear un mensaje indicando que propiedad esta seindo invocada y a que hora. Ahora el ejemplo talvez no tenga mucho sentido, pero sigan leyendo...

Si hicieramos esto con el codigo anterior tendriamos que poner codigo adelante de nuestros llamados (o detras) con la informacion logueada. Tambien podriamos hacer una clase que se encargue de encerrar esa logica de logguear y asignar data en un metodo, o podemos usar el Proxy:


//Primero importemos el namespace flash_proxy que es necesario para hacer override de los metodos de la clase Proxy
import flash.utils.Proxy;
import flash.utils.flash_proxy;

use namespace flash_proxy;

public class class MyProxy extends Proxy {

private var data:Object = new Object();// Este objeto contendra nuestra informacion

//Retorna undefined si la propiedad no existe
override flash_proxy function getProperty(name:*):*
{
trace("Invocando propiedad: " + name);
return data[name];
}

override flash_proxy function setProperty(name:*, value:*):void
{
trace("Agregando propiedad: " + name + " con valor " + value);
data[name] = value;
}

override flash_proxy function callProperty(name:*, ... rest):*
{
//Aqui podemos llamar a otros metodos en esta clase o de otro objeto
//que tengamos referencia dentro de la misma
if(name == "iterate")
{
trace("Contenido del objeto: ");
for each(var val:* in data) {
trace(val);
}
}
}
}


El metodo getProperty es invocado cada vez que alguna instancia de la clase MyProxy le sea invocada una propiedad, algo asi:


var proxy:MyProxy = new MyProxy();

trace(proxy.color);//Getproperty es invocado


El metodo setProperty es invocado cada vez que se setea una propiedad de la instancia:


proxy.color = "verde";//SetProperty es invocado


Y finalmente el metodo callProperty es invocado cuando hacemos esto:


proxy.iterate;


Como pueden ver no se tiene que llamar a proxy.getProperty("color") o proxy.setProperty("color", "verde") o proxy.callProperty("iterate"), sino directamente a las propiedades o nombres de metodos que queremos tener. y el FP se encarga de invocar esos metodos en tiempo de ejecucion. El se encarga de hacer la logica necesaria y la magia la ejecuta el flash player que reconoce cual metodo invocar (getProperty, setProperty, callProperty o el que sea).

Esto es super util como mencione arriba para agregar comportamiento a clases que ya existen, pensando en un AOP mucho mucho mas sencillo pero igualmente efectivo.

Pues finalmente lo que hice con mi SharedObject fue poner un comportamiento parecido al de arriba y entonces logre tratar mi interaccion con el shared object que inicialmente necesitaba al menos 5 lineas, que despues baje a la invocacion de solo un metodo a poder hacer algo como esto:


settings.property = value; //dentro de este llamado esta el try/catch y el flush del SO.


Teoria:

Esto que acabamos de ver es el patron de dise~no Proxy, que como lo indica su nombre es una objeto que toma el lugar de otro. Este patron es usado a traves del Flash Api y Flex Framework en multiples lugares como el Loader donde tenemos acceso a propiedades (width, height) aunque no tengamos acceso al contenido al mismo instante. Tambien el RemoteObject en Flex hace uso de este patron cuando invocamos operaciones directamente del remote Object, por ejemplo: ro_user.loginUser(username,password); en este caso se llama remote proxy, pero es basicamente la misma idea solo que accedemos a datos remotos o externos.

La usabilidad de este patron es bastante amplia y muchas veces es muy despreciado, pero he de admitir que es una solucion muy elegante y sencilla para muchos problemas, ademas que el Flash API nos provee las herramientas necesarias para hacer este tipo de cosas de una manera muy sencilla.

lunes, 16 de noviembre de 2009

Pseudo Threads en Actionscript

Como mencione en un post anterior el Flash Player aunque internamente tiene un sistema de Threads o hilos que permite ejecutar multiples tareas al mismo tiempo, no provee a nosotros los desarrolladores la funcionalidad para utilizar threads nativamente. Esto hace por supuesto que aplicaciones nuestras donde se procesen muchos datos o con funciones o procesamiento muy pesado haga que nuestras aplicacion se congele o se pegue...
Como desarrolladores no tenemos otra forma de hacer que esto funcion sino es emulando la funcionalidad de los threads. Digo emulando porque no hay forma de hacerlo nativamente y se hace dividiendo el proceso pesado en multiples pedazos.
Acerca de esto se ha escrito en multiples lugares con contenido muy completo y excelentes soluciones a distintos niveles de complejidad.
Las librerias anteriores y muchas otras lo que hacen es partir el proceso grande en multiples pedazos que seran ejecutados en momentos distintos. Esto disminuye la carga de trabajo y hace que el proceso no se ejecute de un solo sin permitir al FP refrescarse y por lo tanto pegarse.
Sin embargo de las librerias anteriores, mi favorita es la de Grant Skinner, se llama "Chunker" pues parte los procesos en pedazos. Sin embargo basado en esa clase, decidi hacer unas modificaciones que aqui presento:


package com.grayscale.util.threads
{
import flash.display.Shape;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.getTimer;

/**
* Evento despachado cuando se concluye el proceso.
*/
[Event (type="flash.events.Event", name="complete")]

/**
* Esta clase es una implementacion simple de un pseudo thread en AS3.
*

Esta basada en la clase de Grant Skinner aunque con algunas modificaciones.
* http://www.gskinner.com/libraries/Chunker.zip


*/
public class SimpleThread extends EventDispatcher
{
//Nos permite tener acceso al evento ENTER_FRAME que sera el que lleve el
//paso de cada cuando se ejecutaran nuestros procesos.
private var shape:Shape = new Shape();
//Estado del hilo
private var _paused:Boolean = false;
//Cada cuanto se ejecutara
private var _execTime:uint;
//Funcion a ejecutar
private var _func:Function;
//Argumentos a nuestra funcion. Es un array de elementos que pasariamos a nuestra funcion
private var _args:Array;

/**
* Constructor.
*
* @param execTime Cada cuanto se ejecutara nuestra funcion
* @param func funcion a ejecutar
* @param args parametro opcional con los valores a pasarse en la funcion
*/
public function SimpleThread(execTime:int, func:Function, args:Array=null)
{
_execTime = execTime;
_func = func;
_args = args;

pause = false;
}

/**
* Para el thread o lo arranca
*/
public function set pause(value:Boolean):void
{
_paused = value;
if(_paused) shape.removeEventListener(Event.ENTER_FRAME, run);
else shape.addEventListener(Event.ENTER_FRAME, run);
}


/**
* Metodo que ejecuta nuestra funcion
*/
private function run(event:Event):void
{
var initialTime:int = getTimer();//registra el tiempo donde inicia este iteracion
while(!_paused && (getTimer() < _execTime+initialTime ))//revisa si no hemos excedido la cantidad de tiempo del inicio
{
//llama nuestra funcion y esta tiene que regresar un valor booleano. Si este es falso detiene el thread sino continua.
var res:Boolean = _func.apply(this, _args) as Boolean
if(!res)//ya se termina de ejecutar nuestra funcion, pausamos el thread y despachamos evento avisando que se concluyo
{
dispatchEvent(new Event(Event.COMPLETE));
pause = true;
}
}
}
}
}


El unico requisito para esta clase, es que la funcion que queremos partir debe devolver un valor booleano: true si todavia hay data que procesar, false si ya termino de procesar la informacion.
A continuacion presento dos ejemplos, ambos cargan el mismo archivo(analytics de este blog); uno lo hace sin los pseudo-threads y otro con el pseudo-thread. Podran ver la diferencia como uno se pega y el otro no. Es un archivo grande (4mb) asi que tengan paciencia. Apenas se carga se activa el boton de "Start"
Notas: 1. Debe aparecer un spinner cuando se aprieta el boton de "start". 2. los controles de la pantalla deben ser accesbles mientras se procesan los datos.

Sin Thread.









Con Thread.







Al partir nuestra funcionalidad en multiples ejecuciones y no solo en una, ocupamos una forma de llegar a saber donde terminamos de procesar y desde donde debemos empezar. Para esto puedo sugerir el uso del patron Iterator. Este patron permite a una coleccion encapsular la manera en que se recorre la coleccion y guardar dentro de si misma cual fue el ultimo elemento procesado, sin tener que tener mantener un indice de la coleccion por fuera. El iterador se encarga de todo. Esto es bueno ya que al partir nuestro proceso ocupamos mantener una referencia al dato que estamos procesando sin tener que crear otras variables.
Aqui presento las siguientes clases para tener nuestro iterator.

Interfaz Base:


package com.grayscale.util.iterator
{
/**
* Esta interfaz define los metodos basicos que debera contener un iterador en nuestra coleccion
* @author Ivan Ramirez - ivan.ramirez@gmail.com
*/
public interface IIterator
{
/**
* Devuelve "true" si tenemos mas valores que recorrer dentro de nuestra coleccion
*/
function hasNext():Boolean;
/**
* Devuelve el proximo valor en nuestro iterador
* @returns el siguiente objeto en la coleccion.
*/
function next():*;
/**
* Nos permite reiniciar el recorrido de nuestra coleccion
*/
function reset():void;
}
}


Implementacion basica:


package com.grayscale.util.iterator
{
/**
* Implementacion basica de nuestro iterator para el manejo de arrays. Podemos implementar esta interfaz
* en otras clases para hacer iteradores con Strings o de XML, etc.
* @author Ivan Ramirez - ivan.ramirez@gmail.com
*/
public class ArrayIterator implements IIterator
{
//Coleccion base
private var collection:Array = new Array();
private var index:int;

public function ArrayIterator(values:Array)
{
collection = values
}

public function hasNext():Boolean
{
return index < collection.length;
}

public function next():*
{
return collection[index++];
}

public function reset():void
{
index = 0;
}

}
}


La ventaja de tener una interfaz definiendo el iterador, es que podemos crear nuestras propias implementaciones del iterador de acuerdo a nuestras necesidades.
Ya con nuestro iterador cargado con la coleccion de datos que tenemos que procesar, procedemos a utilizar nuestro thread.

El codigo de las aplicaciones de este ejemplo esta aqui.

miércoles, 16 de enero de 2008

Patron de Comando en Actionscript

Patron de Comando:

Es un patron de comportamiento, que nos permite eliminar el acoplamiento entre objetos.
Ejm:

Objeto A ocupa invocar un servicio del Objeto B. Generalmente se hace a traves de la invocacion directa del servicio ObjetoB.method();
Eso genera un acoplamiento alto, debido a que de esa forma, Objeto A ocupa saber los metodos del Objeto B y si los mismos se llegaran a cambiar alteraria (nombre, firma, etc) la compilacion del Objeto A daria error y habria que modificarlo ahi o en cualquier otro objeto que invoque ese servicio.
Para evitar esto, se procede a crear una clase intermedia (el command), que sera la que conocera todo acerca de la clase B y la cual sera invocada por la Clase A, para ejecutar la tarea.
El Command no se preocupa por la respuesta que se genera o a quien debera retornarla, solo ejecutarla.
Esto se hace a traves de la definicion de una Interfaz con el metodo execute (o ejecutarAccion o ejecutar o como se quiera, pero que todos los comandos implementen ese metodo)

Ejemplos:

Sin Command:

ObjetoA -- invoca metodo --> ObjetoB

Con Command:

ObjetoA -- invoca execute --> Command -- invokes metodo --> ObjetoB

La ejecucion de la accion es desconocida por el que la inicio y eso permite que no exista acoplamiento entre componentes ni objetos y que al mismo tiempo las modificaciones que se hagan mas adelante, no generen errores en clases o componentes que ya estaban listos.
Esto es basicamente lo que sucede con Cairngorm y los comandos que se implementan dentro del framework.

Ejemplo de Codigo (la sintaxis no esta chequeada contra el compilador ni con Cairngorm):

Interface Command

package com.ejemplos.patrones.ejemplo{
public interface ICommand{
public function ejecutar():void; //No devuelve ningun tipo de valor
}
}

Clase CommandoLlamarClaseB

package com.ejemplos.patrones.ejemplo{
public class CommandoLlamarClaseB implements ICommand{

public function ejecutar:void{
var claseB:ClassB = new ClassB();
claseB.llamadoEnClaseB();
}

}
}


Clase A

package com.ejemplos.patrones.ejemplo{
public class ClassB{
public function llamarClaseB():void{
var comando:ICommand = new CommandoLlamarClaseB();
comando.ejecutar();
}
}
}

Clase B

package com.ejemplos.patrones.ejemplo{
public class ClassB{
public function llamadoEnClaseB():void{
trace("Desde Clase B");
}
}
}

lunes, 10 de diciembre de 2007

Llamadas Asincrónicas

Tecnologías como Flex, Ajax, .NET entre otras, hacen uso de lo que se conoce como comunicación asincrónica. Esto es: llamadas a un cierto servicio en las cuales no sabemos cuando se recibirá la respuesta. Hay mucho factores que pueden modificar el tiempo de respuesta de un servicio, como puede ser la carga en el server, bandwidth del cliente, entre otros...
En comunicaciones sincronizadas, la aplicación no continuará trabajando hasta que reciba una respuesta a la petición hecha, en una aplicación asincrónica no.
Pensando en este ambiente, planteo la siguiente situación que se puede presentar en cualquier tecnología asincrónima:

Se tienen dos botones, que se conectan a un mismo servicio (archivo XML, un script PHP, ASP, JSP, un webservice o lo que sea) pero que hacen distintas funciones, se presiona uno primero y medio segundo después el segundo... En la forma en que se programa asincrónimamente, no sabemos cual respuesta va a llegar primero, puede ser la del segundo boton y después la respuesta del primero. Si nos ponemos a programar y pensar "sincronizadamente", esperaríamos la primer respuesta y luego la segunda y esto puede ocasionar problemas en nuestras aplicaciones ya que si el orden es distinto la forma en que se manejará la respuesta variará el procesamiento de la respuesta recibida y por lo tanto el funcionamiento normal de la aplicación.

Solución en Flex

El AsyncToken es una clase usada para manejar llamadas asincronicas... Es aplicable con lo que se conoce como el ACT Pattern o Asyncronous Completition Token. Este patrón se encarga de procesar la acción indicada a la respuesta recibida a una llamada asincrónima. Esto quiere decir que la llamada realizada por el boton 2, no procesara la acción a la respuesta del llamado del botón 1 aunque llegase primero... sino solamente la que esta relacionada con su llamada.

Las funciones principales del AsyncToken son agregar información que puede ser util para identificar la llamada... y permitir definir quien se encargara de procesar los resultados(y sus fallas en caso que hayan).

Como ejemplo para el primer caso que mencione antes (identificacion de quien hizo una llamada), al trabajar asincronimamente no sabemos cuando iremos a recibir el resultado, en el ejemplo anterior de los botones que se conectan a un mismo remote object pero hacen distintas funciones, se presiona el primero e inmediatamente el segundo.. como va a saber el Result Handler cual de los dos llamados fue invocado? El ASyncToken nos permite agregar cierta informacion que permitira marcar cada llamada y asi se sabra como procesar cada
informacion.... Este token sera agregado al llamado, así que cuando se reciba información el token va a ir pegado con el evento resultado.
Por ejemplo (muy basico) utilizando una "bandera" en el token, que se llamará marker:

//Ejecutado cuando se presiona Boton 1.
private function llamada1():void{
var token:AsyncToken = remote_object.agregarUsuario(instancia_usuario);
token.marker= "agregarUsuario";
}

//Ejecutado cuando se presiona Boton 2.
private function llamada2():void{
var token:AsyncToken = remote_object.modificarUsuario(instancia_usuario);
token.marker= "modificarUsuario";
}

private function resultHandler(event:ResultEvent):void{
var token:Object = event.token;//se carga desde el evento, el token que se instanció en cada función
if(token.marker == "agregarUsuario"){

//codigo para manipular resultado cuando se agrega usuario

}else if(token.marker == "modificarUsuario"){

//Codigo para manipular resultado de modificar usuario...

}
}

Ya en Cairngorm especificamente, en el delegate se utiliza esta funcionalidad, ya que permite asignar quien se encargara de procesar los resultados de una llamada a servicio externo. Generalmente en la comunidad de flex, se le encarga esa responsabilidad a los comandos, por eso los comandos con llamados a datos externos (remote objects, web services o http services) generalmente implementan la interfaz IResponder, que expone los servicios: result(en caso de resultado satisfactorio) y fault (en caso de error). Lo que permite concretamente el asynctoken en este caso, es asignar a otra clase el manejo de los resultados que se vayan a recibir, ej desde un delegate:

var call:AsyncToken = service.agregarUsuario(instancia_usuario);
call.addResponder(responder);

En este caso, quien manejara los resultados del metodo agregar usuario, no sera el delegate, sino el objeto Responder, que será un objeto de un tipo de Clase que implemente IResponder (como mencione antes) y que generalmente es el command, aunque se puede hacer aun en otra clase, para "favorecer la composicion sobre la herencia", pero eso es tema de otro topic...

Así de sencillo, lo bueno es que por la arquitectura de servicios que tiene el Flex, esta misma solución es aplicable a Web Services, HTTP Services y Remote Objects.
Saludos

sábado, 10 de noviembre de 2007

Notas acerca de Cairngorm

Debo de admitir que después de muchos años, cuando ingrese al mundo de Flex, me pareció como un nuevo inicio para quitar vicios de mi programación en Java.
Uno de esos era la dependencia a ciertos frameworks como struts, spring, hibernate, etc. No es que los frameworks sean malos de hecho casi todo lo que hacemos, lo hacemos basados en un framework, pero algunas veces cuando se plantea un problema por resolver muchas veces se piensa directamente en como resolverlo para y con X o Y framework, en lugar de buscar resolver el problema de la mejor manera aunque no haga uso de un framework...
Cuando empecé a adentrarme en Flex, empecé a encontrarme con la palabra Cairngorm muy frecuentemente y como estaba siendo utilizado por bastantes desarrolladores de Flex. El Cairngorm según Adobe es una micro arquitectura y al mismo tiempo un framework. Es un conjunto de patrones de diseño que han sido recolectados a través de varios años.
Por bastante tiempo estuve en negación, no quise estudiar ni adentrarme en Cairngorm, hasta que después de varios meses, en un proyecto sencillo, pero que necesitaba otro tipo de solución a la que estaba empleando normalmente, decidí probarlo.
La verdad me arrepiento de no haberlo usado antes, muchas de las cosas que hice antes, se hubiesen podido resolver de una mejor manera haciendo uso del framework... ayudando a resolver muchos problemas de arquitectura, forzándote a usar algunos de los patrones de diseño.
En realidad es bastante complicado y no es algo que se aprende de la noche a la mañana, se necesita mucha experiencia para agarrarle el ritmo, pero cuando empiezas a entender el funcionamiento aún más de lo que entiendes la sintaxis o forma de implementación, cambiará la manera en que se pueden resolver ciertas RIAs, se buscará arquitecturas donde se busque reducir el acoplamiento, delegar en otras clases, programación a la Interface, uso de Singletons(de por si la aplicación es un cliente, una sola persona la usara...), etc, etc..
A continuación algunos conceptos básicos que mi primer experiencia con Cairngorm ha brindado, estoy seguro que no son todos y talvez no los entienda 100%, pero espero aprender muchos más y que le sirva a alguno que quiera iniciar con esto.

Va más o menos así: Componente --> Patron (es) q implementa --> Descripción

Eventos --> Observer --> Extienden la clase CairngormEvent y son utilizados para notificar a un controlador cuando hay una interacción de un usuario en la que se deba ejecutar algún proceso o comando
Commands --> Command Pattern --> Implementan la interfase Command, forzando a tener un método que se llama Execute, que recibe un evento de parámetro. Aquí es donde se realizaría la acción, sea comunicarse con un server o cualquier cosa que se quiera realizar, la lógica del negocio.
ModelLocator --> Singleton --> Mantiene una copia de toda la información que se maneja del dominio de la aplicación y la pone disponible a las demás "vistas" por medio de binding u otros métodos de setteo. No tiene gran lógica, solo una colección de los datos que se utilizan a través de la aplicación.
FrontController --> FrontController, Singleton --> Se instancia al inicio de la aplicacion y su tarea es registrar los distintos eventos que puedan suceder y los comandos o acciones que se quieran ejecutar en respuesta a esos eventos, desde un solo lugar. Es el que controla los hilos del juego...
Delegates --> Business Delegate --> Se encarga de realizar la comunicación y manejar las respuestas con un servidor (en caso que se ocupe realizar)
Service Locator --> Singleton --> Permite accesar a los distintos servicio de interacción con servidores que se tengan, sean servicios HTTP, acceso a WebServices, Remote Objects, etc... de una manera centralizada y sin tener que declararlos muchas veces, pues están declarados en un solo lugar.

Cairngorm no será la solución para todos los problemas, pero definitivamente hace que uno cambie la manera de pensar en como resolverlos. Igual que con todos los frameworks, "Úsese con cuidado y moderacion", no sea que se piense en como resolver el problema con X Framework, pero ni si quiera se entienda como resolverlo...
Para un verdadero entendimiento de la arquitectura y funcionamiento del Cairngorm, no dejen de visitar este diagrama. De verdad aclara el entendimiento.

PS: De verdad.. visiten el diagrama para que puedan entenderlo bien!