lunes, 23 de junio de 2008

Reflection en Actionscript - Parte 1

Comienzo una serie de dos temas acerca de reflection en Actionscript y Flex.
Cuando hablo de Reflection no me refiero al efecto visual que se genera cuando una imagen o parte de la misma es reflejada en otra area.

El reflection al que me refiero es a la facultad de un programa para que en tiempo de ejecucion pueda examinar su estructura y la de su ambiente y poder modificar lo que hace dependiendo de lo que encuentre. Es una tecnica presente en lenguajes de programacion recientes.

En Java por ejemplo, la funcionalidad de reflection se encuentra dentro del paquete java.lang.reflection, de donde se encuentran toda una serie de clases y metodos para poder examinar la estructura clases y tomar desiciones basados en esa informacion. En Actionscript esta funcionalidad esta basicamente incluida en cuatro funciones que veremos mas adelante.

Debo admitir que el uso de reflection en nuestras aplicaciones no es algo de todos los dias, sin embargo las veces que es utilizada se presenta como una solucion muy elegante para ciertos problemas.

Un poco de mi experiencia personal con reflection:

Mi primer contacto con reflection fue hace como unos 5 a~nos. Ingresaba a laborar en una pequen~a empresa en Miami. No habian muchos empleados aunque si muchos clientes y sobre todo un sistema muy robusto y muy bien disenado que cumplia con todas las necesidades y mas de la empresa. El programador lider era un excelente arquitecto. Tenian un sistema que se conectaba a 6 distintos proveedores - con conectividad e interaccion distinta en cada uno - a traves de un framework inventado en la empresa, que con el uso de interfaces y de reflection lograba en tiempo de ejecucion descargar y cargar las librerias de conectividad e interaccion para los distintos proveedores y realizar la funcionalidad necesaria. Todo era configurado desde un XML y si se necesitaba agregar un nuevo proveedor, se creaba la nueva libreria (.jar en ese caso) y se agregaba en el XML. Reflection hacia toda la magia de la carga de las clases y de encajarlo todo dentro de la aplicacion sin tener que compilarla en ningun momento.

Luego pase a aplicar reflection dentro de aplicaciones Web y de escritorio. Cada vez era mas sencillo utilizar el reflection en las aplicaciones y agregar funcionalidad en tiempo de ejecucion sin tener que compilar mi aplicacion nuevamente. Con la ayuda de un gran libro logre ir aprovechando mejor la herramienta, hasta que migrando de Java a Flex, pude descubrir la funcionalidad que brinda Actionscript y logre anadirla en algunas aplicaciones.

Manos a la obra:

Actionscript provee en el paquete flash.utils una serie de funciones para manejar reflection:

describeType: Recibe un objeto como parametro y devuelve un XML con la descripcion de la clase de la cual es el objeto.

Supongamos que tenemos la siguiente clase:



   1:  package 

   2:  {

   3:      public class Perro

   4:      {

   5:          

   6:          public var nombre:String;

   7:          public var raza:String;

   8:          public var peso:Number;

   9:          public var color:String;

  10:   

  11:          public function ladrar():void

  12:          {

  13:              trace("GUAW GUAW");

  14:          }

  15:   

  16:      }

  17:  }





Aplicamos describe type:

   1:  var bulldog:Perro = new Perro();

   2:  describeType(bulldog)



Salida:




   1:   

   2:  <type name="Perro" base="Object" isdynamic="false" isfinal="false" isstatic="false">

   3:   <extendsclass type="Object">

   4:   <variable name="peso" type="Number">

   5:   <method name="ladrar" declaredby="Perro" returntype="void">

   6:   <variable name="color" type="String">

   7:   <variable name="raza" type="String">

   8:   <variable name="nombre" type="String">

   9:  </variable>



Una vez que tengamos toda la informacion de la clase variables, accessors, metodos, super clase, etc; podremos ser capaces de acceder a la informacion o invocar los metodos que necesitemos.

getDefinitionByName: Recibe un String como parametro con el nombre completo de una clase y devuelve (si existe) un objeto del tipo clase asignada por parametro que puede ser casteada posteriormente como un Class.

Utilizando la misma clase Perro del ejemplo anterior:




   1:  var clazz:Class = getDefinitionByName("Perro") as Class; //Puede ser getDefinitionByName("paquete.de.la.clase.Perro")

   2:  var miPerro:Object = new clazz();



Se crea una clase del tipo pasado en el String de parametro. Pueden ser clases del framework de Flex o de API de Actionscript o customizadas, como este caso. Solo se ocupa que se contenga la ruta completa (incluyendo el paquete)

El unico problema que tiene esto es que:
  • El compilador, para reducir el tamano de los swfs no incluye en el swf final los archivos de clases que no son utilizadas en algun momento desde nuestra aplicacion. Esto quiere decir que si en ningun otro lado de la aplicacion se crea una nueva instancia de la clase Perro, esta no sera incluida dentro del SWF final y el uso de reflection generara error algo como "ReferenceError: Error #1065: Variable is not defined.". Esto le quita un poco la funcionalidad al reflection ya que te limita a clases que esten instanciadas dentro de la aplicacion. Sin embargo vamos a ver en el siguiente post como podemos crear aplicaciones utilizando reflection a las que podremos anadir funcionalidad en tiempo de ejecucion y sin tener que compilar la aplicacion principal.

getQualifiedClassName
: Recibe un objeto como parametro y devuelve un string con el nombre completo de la clase del cual es tipo el objeto.




   1:  var clazz:Class = getDefinitionByName("Perro") as Class; //Puede ser getDefinitionByName("paquete.de.la.clase.Perro")

   2:  var miPerro:Object = new clazz();

   3:   

   4:  trace( "Objeto Creado de tipo: " + getQualifiedClassName(object) );



Salida:

Objeto Creado de tipo: Perro

getQualifiedSuperclassName: Recibe un objeto como parametro y devuelve un string con el nombre completo de la super clase del cual es tipo el objeto.

Es parecido al ejemplo anterior.

Esto es todo por ahora, en el siguiente post presentare dos aplicaciones del mundo real que se le puede dar al reflection desde actionscript, uno un sencillo serializador de clases a XML y el otro una aplicacion que carga desde un XML distintos proveedores en tiempo de ejecucion y que permite anadir nuevos proveedores sin tener que compilar la aplicacion principal.

2 comentarios:

fusa dijo...

Felicitaciones por el post..., muy util, espero sacar poder utilizar esta tecnica en mis proyectos...

Ivan dijo...

Gracias, espero que asi lo sea!