martes 25 de septiembre de 2007

Reflection en ActionScript 3

Los lenguajes orientados a objetos suelen incorporar mecanismos para conocer información de los objetos en tiempo de ejecución. Actionscript no es una excepción.
El concepto de Reflection en lenguajes orientados a objetos no tiene nada que ver con el conocido efecto gráfico que muestra un reflejo de un componente.
Se trata una técnica de programación que permite crear clases, invocar métodos y acceder a variables incluso cuando no sabemos los nombres de las clases,
métodos o propiedades hasta el momento de la ejecución.
Utilizando Reflection podemos crear componentes totalmente genéricos, que funcionen con cualquier tipo de objeto.

Si eres programador de java, seguramente te suene el paquete java.lang.Reflect que se utiliza para hacer este tipo de cosas.

Vamos a ver los conceptos básicos de las técnicas de Reflection en ActionScript y un sencillo ejemplo para que veáis en código cómo se hace.
Las funciones básicas para realizar reflection en actionscript se encuentran en el paquete flash.utils y nos permiten recuperar un xml que contiene toda la información del objeto:

  • Nombre de la clase del objeto

  • Clase de la que hereda

  • Si se trata de un objeto dynamic, final o static

  • Las variables del objeto

  • Los métodos de acceso (comunmente llamados getters y setters)

  • Métodos del objeto

  • ... etc




También contamos con técnicas para crear clases cuyos nombres no conocemos hasta el momento de la ejecución. Así como invocar métodos o acceder a propiedades. Todo ello recuperando la información en tiempo de ejecución.

Con esta técnica podemos hacer componentes y aplicaciones totalmente genéricas y aplicables a cualquier tipo de objeto.

Muchos componentes del framework de flex utilizan algunas técnicas de reflection, por ejemplo el DataGrid.
Un datagrid no conoce el tipo de objeto que va a albergar hasta el momento de la ejecución.
Nosotros le indicamos en tiempo de compilación los dataField (los nombres de las propiedades).
Es en el momento de la ejecución cuando el datagrid recupera esas propiedades de los objetos que contiene,
independientemente de la clase de los objetos.

En actionScript, recuperar el valor de una variable de un objeto es realmente sencillo. Basta con tratar el objeto como si se tratase de un array asociativo, donde el índice es el nombre de la propiedad:

objeto ["nombreVariable"]


Recuperar información sobre un objeto es un poco más complicado. La función flash.utils.describeType devuelve un XML con información sobre el objeto


describeType (objeto)

Veamos un ejemplo. Tenemos la siguiente clase:

package com.gonzalopezzi.asreflection.vos

{
public class Persona
{
public function Persona () {
_id = (new Date ()).time;
}
private var _id : Number; // Esta propiedad es de sólo lectura (ver getter)
public var nombre : String;
public var apellidos : String;
public var nif : String;
public var fechaNacimiento : Date;
public var telefono : String;
public var prioridad : Number;
public function get id () : Number {
return _id;
}
public function dummy (a : Number, b : String) : String {
return "dummy";
}
}
}




Veamos qué ocurre si invocamos la función describeType con una instancia de esa clase. Obtenemos el siguiente xml:


<type name="com.gonzalopezzi.asreflection.vos::Persona" base="Object" isDynamic="false" isFinal="false" isStatic="false">
<extendsClass type="Object"/>
<variable name="fechaNacimiento" type="Date"/>
<variable name="nif" type="String"/>
<variable name="apellidos" type="String"/>
<method name="dummy" declaredBy="com.gonzalopezzi.asreflection.vos::Persona" returnType="String">
<parameter index="1" type="Number" optional="false"/>
<parameter index="2" type="String" optional="false"/>
</method>
<variable name="prioridad" type="Number"/>
<variable name="telefono" type="String"/>
<variable name="nombre" type="String"/>
<accessor name="id" access="readonly" type="Number" declaredBy="com.gonzalopezzi.asreflection.vos::Persona"/>
</type>


Con ese objeto XML y con la ayuda de sencillos operadores E4X, podemos conocer de forma instantánea toda la información que necesitamos de un objeto en tiempo de ejecución.

Pero nos falta algo. Todavía no sabemos cómo instanciar un objeto de una clase cuyo nombre no conocemos hasta el momento de la ejecución. Es sencillo. Veamos:

var clase : Class = getDefinitionByName(nombreClase) as Class;
var p : Object = new clase ();

¡Pero cuidado! Aquí nos encontramos con una gran limitación. Si intentamos ejecutar esto y le pasamos un nombre de clase que no se referencia en ningún lugar de la aplicación, vamos a obtener
un error. ¿Por qué ocurre esto? El compilador intenta economizar el peso del swf compilado. Para ello, no incluirá en la compilación las clases que no se usen, aunque estén dentro de nuestra carpeta de fuentes.

Típica pregunta: ¿Y si pongo un import para importar esa clase? ... así no hacemos nada. Aunque tengamos el import, si no hemos instanciado una variable de esa clase, no conseguiremos nada.

La solución: crear una clase con variables de los tipos que sabemos que podremos instanciar en tiempo de ejecución e instanciar esa clase en algún lugar de nuestro código. (ver clase ClassLinker en el ejemplo)

Aquí tenéis un pequeño ejemplo para que podáis ver todo esto en acción.

Las posibilidades de este tipo de técnicas son muy variadas y potentes. Podemos mejorar la productividad de nuestro equipo de desarrollo si creamos componentes y código que utilice objetos de forma genérica. Podremos crear también, aplicaciones mucho más flexibles y adaptables orientando nuestro desarrollo a la creación de interfaces con métodos bien definidos, enlazando las clases de implementación de las interfaces en tiempo de ejecución. Este tipo de técnicas constituyen un punto de partida esencial para motores de inyección de dependencias (también conocido como IoC, o Inversión de Control).

El desarrollo de aplicaciones web vuelve a ser divertido. Disfrutad.

miércoles 3 de enero de 2007

Arte


Una de mis aficiones son la pintura y el diseño gráfico.
Acabo de terminar esto. Es un paisaje basado en unas fotos que tomé hace tiempo en un bosque. (Pinchad en la imagen para verla en mejor resolución)

Si queréis ver algunos ejemplos más, entrad en mi dirección de deviantart.



domingo 31 de diciembre de 2006

Cómo crear componentes en Flex 2

Dano ha subido el primero de doce artículos que publicará a lo largo de 2007 sobre la tecnología Adobe Flex. En este caso nos explica cómo hacer componentes Flex. Un artículo muy bueno y didáctico. No os lo perdáis.

sábado 30 de diciembre de 2006

Internacionalización de aplicaciones Flex

En J2EE es habitual crear aplicaciones multi-idioma. Los frameworks de desarrollo de aplicaciones web J2EE incluyen mecanismos para hacer páginas multilingües sin demasiado esfuerzo.
Además de la internacionalización, cuando se programa de esta forma, se observa una gran ventaja: tendremos una gran flexibilidad durante el mantenimiento al tener todos los textos de nuestra aplicación centralizados en ficheros (.properties, habitualmente). Los clientes son caprichosos con los textos que aparecen en las aplicaciones y en ocasiones algunos textos resultan confusos para los usuarios y necesitan ser modificados.
En aplicaciones Flex surgen ciertos problemas a la hora de implementar la internacionalización:

  • A diferencia de J2EE, las páginas que se muestran no se preparan dinámicamente en el servidor para un usuario concreto. En nuestro caso tenemos una aplicación cliente compilada en un fichero ".swf". Por lo tanto, lo lógico es que los textos de la aplicación estén dentro de ese "swf".

  • Incluir todos los idiomas dentro del mismo "swf" repercute en el tamaño de la aplicación cliente descargada por el usuario.


En consecuencia, habrá que recuperar los textos de la aplicación en tiempo de compilación y compilar la aplicación cliente para cada idioma al que queramos dar soporte.
Flex incluye mecanismos para este propósito. Veamos un pequeño ejemplo:







<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" verticalAlign="middle"
horizontalAlign="center" viewSourceURL="sourceview/index.html">
<mx:Panel width="320" height="200">
<mx:Label text="@Resource(bundle'mensajesAplicacion', key='saludo')"/>
</mx:Panel>

</mx:Application>






Parece fácil, ¿verdad? Bueno, es que en realidad ahí no acaba todo.
Habéis visto que hemos hecho referencia a un bundle que se llama MensajesAplicacion, pues bien, tendremos en algún lugar de nuestro sistema de archivos una carpeta resources que contiene a su vez una carpeta para cada idioma (en_US, fr_FR ...). Dentro de cada carpeta de idioma, meteremos un fichero MensajesAplicacion.properties traducido.
Ya sólo queda una cosa: tendremos que indicar al compilador qué idioma para compilar:


-locale es_ES -sp C:\SRC\resourceBundle\resources\{locale}


Espero que os sirva de ayuda. Muchas gracias por vuestra atención.

martes 26 de diciembre de 2006

SequenceCommand: comandos encadenados


Bjorn Schultheiss ha publicado un artículo excelente sobre Commands encadenados con Cairngorm.
Para los que no conozcáis este framework, os invito a leer con detenimiento
este tutorial.

Los que conocéis Cairngorm, quizá no sepáis que a partir de la versión 2.0 de Cairngorm, las clases Command heredan de SequenceCommand. De este modo, es posible encadenar eventos de forma sequencial.

Esto es muy interesante, sobretodo si queremos evitar que un cliente haga varias llamadas simultáneas a servidor, para evitar una carga excesiva del mismo.

Pues bien, el uso de dichos SequenceCommand, tal y como propone Cairngorm, es un poco lioso y el resultado es un código difícil de mantener.

Sin embargo, Bjorn Schultheiss ha creado una
solución muy elegante para el control secuencial de los comandos, basada en los SequenceCommand de Cairngorm.