sábado, 28 de junio de 2008

Reflection en Actionscript - Parte 2 - A

Esta es la segunda parte del tutorial sobre reflection. Este esta mas orientado a aplicaciones de la vida real que le podemos dar a reflection. Voy a dividir la parte en dos por lo largo que toman la explicacion de los ejemplos.

Ejemplo 1:

Serializador


Problema:

Se ocupa serializar los objetos de una aplicacion en XML para ser enviados al servidor con sus respectivos valores, nombre de los campos y tipos de los mismos.

No se desean modificar las clases ya construidas.

Solucion:

Para empezar nuestro ejemplo vamos a tomar las siguientes clases de Actionscript. Son tres clases simples describiendo tres abstracciones distintas y sin relacion. Estas clases seran las que tendremos que serializar en un XML. Como no se quieren alterar las clases, se crea una clase utilitaria que se encargara de realizar esta serializacion.

A continuacion la descripcion de las clases:
package serializador.classes
{
public class Perro
{

public var nombre:String;
public var raza:String;
public var peso:Number;
public var color:String;

public function ladrar():void
{
trace("guaw guaw!");
}

}
}
package serializador.classes
{
public class Carro
{

public var marca:String;
public var fabricante:String;
public var anho:Number;
public var motor:Number;

}
}

package serializador.classes
{
public class Persona
{

public var nombre:String;
public var apellidos:String;
public var edad:Number;
public var sexo:String;
public var altura:Number;

}
}

Lo dificil de esta solucion (sin usar reflection) es que se tendria que crear un serializador para cada una de clases (ya que entre ellas no tienen relacion) para poder acceder a cada una de las variables o metodos que se tenga en cada clase (ya que todo esto es desconocido).

Pero con reflection las cosas cambias ya que en tiempo de ejecucion puedo averiguar los metodos, variables y accesors que tiene una clase. Con esto hacemos un metodo que reciba de parametro un objeto y utilizando describeType nos devuelve un XML con la descripcion completa de la clase y lo mejor es que podemos aplicar la solucion a cualquier clase que se quiera sin tener que hacer nada nuevo.

Masomenos algo asi es lo que nos devuelve la funcion describeType:


<type name="Perro" base="Object" isdynamic="false" isfinal="false" isstatic="false">
 <extendsclass type="Object">
<variable name="peso" type="Number">
<method name="ladrar" declaredby="Perro" returntype="void">
<variable name="color" type="String">
<variable name="raza" type="String">
<variable name="nombre" type="String">
</variable>
Esta es la funcion que hacemos:


public static function serialize( item:Object ):XML
{
var descripcion:XML = describeType(item); // invoamos a funcion para describir la funcion. Nos retorna un XML
var root:XML = new XML("<Object type=\""+ descripcion.@name +"\"/>"); //Creamos un nuevo XML que devolveremos posteriormente.

for each (var variable:XML in descripcion.variable){//del XML navegamos por todos los elementos dentro del nodo de Variables

// Creamos un nuevo nodo, su nombre es el de la variable (cargada del XML), el tipo se carga igualmente de la descripcion que encontramos
// en el XML que genera describeType y el valor lo hacemos usando Introspeccion en el objeto pasado por parametro invocando la
// variable por medio de objeto[ variable ]
var node:String = "<property name=\"" + variable.@name + "\" type=\""+ variable.@type + "\">" + item[variable.@name] + "</property>";

root.appendChild(node);//agrega al nuevo XML
}

return root;//retorna nuevo XML con nuestra serializacion
}


Este es el resultado de nuestra funcion pasando de parametro instancias de las clases Carro, Perro y Persona (en ese orden):
<Object type="serializador.classes::Carro">
<property name="fabricante" type="String">Nissan</property>
<property name="marca" type="String">Maxima</property>
<property name="anho" type="Number">2003</property>
<property name="motor" type="Number">1300</property>
</Object>

<Object type="serializador.classes::Perro">
<property name="color" type="String">Cafe</property>
<property name="peso" type="Number">25</property>
<property name="raza" type="String">Bulldog</property>
<property name="nombre" type="String">Bruno</property>
</Object>

<Object type="serializador.classes::Persona">
<property name="altura" type="Number">1.6</property>
<property name="edad" type="Number">38</property>
<property name="apellidos" type="String">Muller</property>
<property name="sexo" type="String">Masculino</property>
<property name="nombre" type="String">Steven</property>
</Object>
Como dije anteriormente la ventaja de esta solucion es que podemos usar cuantos objetos queramos de distintas clases sin tener que alterar nada en nuestra funcion de serializar.

2 comentarios:

Janther dijo...

Felicitaciones por tu blog.

Describes todos los pasos y posibles usos muy bien.

En el primer post sobre reflection y flex dijiste que ibas a explicar como cargar clases no compiladas en tiempo real.

Se que ha pasado un año pero podrias volver postear sobre el tema por favor.

De antemano muchas gracias

Ivan dijo...

Hola Janther! Gracias por el comentario... a veces siento que hablo contra una pared :) pero ver que la gente esta interesada en el tema se siente mucho mejor...
Prometo hablar de este tema pronto!
Gracias!