Cairngorm VII: Business Delegate

En el post anterior vimos que los commands son stateless y que son el núcleo funcional de las distintas partes de una aplicación. Poniendo el ejemplo de “cargar los datos de un usuario dadoï¿Â½? veamos cómo abordaríamos su implementación a alto nivel.

El command tendría que utilizar un service que le permitiera establecer una conexión con la parte servidora. Si por ejemplo tenemos una página .aspx, .jsp, .php, un servlet, etc que pasándole como parámetro un id nos devuelve en formato xml la información de un usuario. Tendríamos que declarar este service en nuestro serviceLocator.

Posteriormente podríamos invocar la petición desde cualquier command. Veamos un pequeño ejemplo:

[ftf w=”500″ h=”300″]
package
{
import com.adobe.cairngorm.control.CairngormEvent;
import com.adobe.cairngorm.commands.Command;
import com.adobe.cairngorm.business.ServiceLocator;
import mx.rpc.http.HTTPService;

public class TestCommand implements Command, IResponder
{
public function execute(event:CairngormEvent):void
{
var service:HTTPService = ServiceLocator.getInstance().getHTTPService(“myService”);
service.send();
}
}
}[/ftf]

La implementación podría quedar así y sería totalmente válida. Pero fijémonos que en ningún lado hemos hablado de lo que se hará una vez se obtenga la respuesta de la invocación del servicio. Seguramente un servicio o un método de este pueda invocarse de distintas formas (comando) y cada una de ellas tratará los resultados de una forma distinta.

Vemos entonces que la invocación de los servicios tiene que parametrizar siempre la forma de tratar la respuesta. Para solventar esto se introduce el concepto de Responder. A nivel implementacional no es más una interface que define un método result y otro fault que se ejecutarán cuando el resultado de la invocación del service sean satisfactoria o no.

[ftf w=”500″ h=”500″]
package com.madeinflex.pod.commands
{
import com.adobe.cairngorm.control.CairngormEvent;
import mx.rpc.IResponder;
import com.adobe.cairngorm.commands.Command;
import com.adobe.cairngorm.business.ServiceLocator;
import mx.rpc.http.HTTPService;
import mx.rpc.AsyncToken;

public class TestCommand implements Command, IResponder
{
public function execute(event:CairngormEvent):void
{
var service:HTTPService = ServiceLocator.getInstance().getHTTPService(“myService”);
var pendingCall:AsyncToken = service.send();
pendingCall.addResponder (this);
}

public function result(data:Object):void
{
trace (“resultado obtenido”);
}

public function fault(info:Object):void
{
trace (“fallo en la invocación”);
}

}
}[/ftf]

Paralelamente a este problema en un desarrollo distribuido cliente/servidor normalmente trabajan distintos perfiles: especialistas cliente y especialistas servidor. Es muy normal que las fases de desarrollo cliente / servidor se paralelicen, de tal forma que el desarrollo de la parte cliente pueda continuar sin necesidad de que la parte servidora esté completa.
Esta es una de las justificaciones del patrón Business Delegate, el cual permite crear una capa temporal que gestione las respuestas y que en determinadas situaciones pueda simular una parte del aplicativo aún por desarrollar devolviendo Mock Objects (Objetos generados de forma hard coded que emulan una posible respuesta).

Resumiendo, los Business Delegate nos permiten gestionar la forma en cómo tratar las respuestas recibidas desde el servidor así como el simularlas agilizando el desarrollo.

Tal como comentábamos en el punto uno (Value Objects), en un aplicativo se debería tratar siempre con ValueObjects transversales a la tecnología utilizada en las distintas capas, es conveniente tratar con objetos que no comprometan el futuro de nuestras aplicaciones. Tal como comentábamos aunque nuestro aplicativo consuma datos dinámicos en formato XML, SOAP, etc. es muy interesante convertirlos a VO’s. Los delegates al tener el control sobre las invocaciones al servidor y a sus respuestas, es el sitio ideal donde hacer el tratamiento de la información recibida y por ejemplo parsear de XML a VO’s.

Los delegates también son la parte que aislan la aplicacición de la tecnología utilizada en el servidor. Si tenemos un aplicativo que consume datos en formato XML y queremos pasar a utilizar FDS o cualquier otra solución basada en AMF sólo tendríamos que cambiar el delegate.
Veamos un ejemplo de un delegate:

[ftf w=”500″ h=”500″]
package com.madeinflex.pod.business
{
import mx.rpc.IResponder;
import mx.rpc.http.HTTPService;
import com.adobe.cairngorm.business.ServiceLocator;
import mx.rpc.AsyncToken;
import flash.net.URLVariables;

public class HttpUrlDelegate
{
private var responder:IResponder;
private var service:HTTPService;

public function HttpUrlDelegate (responder:IResponder) {
this.responder = responder;
this.service = ServiceLocator.getInstance().getHTTPService(“feedService”);
}

public function loadFeed (feedUrl:String):void {
var req:URLVariables = new URLVariables();
req.action = “proxyRequestï¿Â½?;
req.URL = feedUrl;
var pendingCall:AsyncToken = this.service.send(req);
pendingCall.addResponder (this.responder);
}

public function loadNews ():void {
var req:URLVariables = new URLVariables();
req.action = “readFeedï¿Â½?
req.feed = “rss2”;
req.cat = 4;

var pendingCall:AsyncToken = this.service.send(vars);
pendingCall.addResponder (this.responder);
}
}
}[/ftf]

Un uso muy potente que podríamos dar a los delegates consistiría en definirlos implementando una interface. Si tenemos varias implementaciones, estas serían intercambiables. Si en los commands referenciármos al delegate a través de su interface y no a través de su implementación concreta obtendríamos un sistema capaz de consumir los mismos datos pero a partir de fuentes distintas. Esta solución se podría usar por ejemplo en sistemas de alto tráfico donde en determinados momentos convendría consumir datos de forma dinámica (FDS, xml dinámico a partir de .phh, .asp, .jsp, servlets, etc) o a partir de ficheros estáticos en formato xml previamente generados en el servidor.

Xavi es un Technical Arquitect de Aplicaciones RIA basadas en la Plataforma Flash trabajando para Adobe en Londres. Especializado en aplicaciones colaborativas en tiempo real, e-learning y CMS (Content Management Systems) utiliza Flex, LCDS, BlazeDS, FMS y Java principalmente.

Sitio Web:http://www.code4net.com

6 Comentarios

  1. ivanhoe

    Xavi te felicito por la manera tan sencilla de explicarnos este patron de diseño, que como bien mencionas oculta la forma de implementar la logica de negocio y separa una capa de otra, logrando un bajo acomplamiento!!

    Saludos a todos los que forman MadeInFlex!!

  2. jesús

    Muy interesante serie de artículos.

    Me parece una buena idea lo que se propone hacer cairngorm aunque me parece muy grande para usarla en proyectos pequeños.

    En fin… como mencionas en el artículo, se podría hacer un mock de un servicio para hacer pruebas sin tener un servidor, etc.. la duda que tengo es si se define fácilmente en el Services.mxml o es mejor inyectarlo con algún método setter en el delegate.

    Otra cosa: alguien sabe de librerías para crear mocks en as3? he visto que está as2lib aunque no la he estudiado y sólo es para as2

    Saludos a la gente de MadeInFlex

  3. Hernán

    Una consulta:

    Necesito identificar el resultado de 2 eventos diferentes.
    El caso es el siguiente:

    En una pantalla tengo varios combos, se dispara un evento para completar la informacion del 1er combo. Luego se dispara un segundo evento para completar el 2do combo.

    El problema es que no puedo determinar a cual de los 2 eventos corresponden los resultados ().

    Saben alguna solución para esto ?

    Muchas gracias,
    Hernán.

  4. Carlos Rovira

    Hernán,

    Cada evento está mapeado a un comando, y este suele tener un result ya que el delegate asigna el comando como un responder. Por tanto, la función result en el comando será la que obtenga el objeto result originado por tu evento.

  5. Miguel

    Hola,
    Una pregunta en relaciión a la ultima,..
    Tengo un sitio que genera varios combos iguales, que se proveen del mismo servicio de datos enviandole diferentes atributos, por ejemplo atributo idioma.
    La situación es como se generan dinamicamente no puedo asignar el resultado a una variable global bindable de las combos. porque me cambiaría todas las combos y tampoco puedo hacer varias variables porque no se cuantas combos se generan. cual es la solución aproximada, alguna idea??
    Muchas Gracias, enhorabuena por el blog.

Deja un comentario

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

Acerca de Made In Flex

Made In Flex es una comunidad de desarrolladores de Apache Flex creada en 2006.

Apache Flex, anteriormente conocido como Adobe Flex, es un SDK (kit de desarrollo de software) para crear aplicaciones enriquecidas - multiplataforma basadas en Adobe Flash donado por Adobe a la fundación Apache in 2011 y promocionado a proyecto de primer nivel en Diciembre de 2012.

Actualmente estamos cambiando muchos aspectos del sitio web para ofrecer un sitio útil para toda la comunidad que tenga en cuenta las necesidades actuales.

Últimas Fotos

Instalador de Apache Flex

Entrar o Registrase