Bloques estáticos en AS3

Los bloques estáticos son bloques de código pertenecientes a una clase que se ejecutan una única vez cuando la clase en cuestión es cargada por primera vez en la AVM.
Dentro de un bloque estático se puede ejecutar cualquier tipo de expresión y referenciar a otras clases pero se debe tener en cuenta que desde el bloque, al estar dentro del ámbito de la clase (no de la instancia, de ahí que se llamen bloques estáticos), solo se pueden referenciar las propiedades y métodos estáticos de la clase.
Un bloque estático es equiparable a un constructor pero dentro del ámbito de clase (no de instancia).

El siguiente código muestra el uso de un bloque estático a modo de inyección de dependencias dinámico:

Actionscript:
  1. /* Archivo.as */
  2. package com.joangarnet.persistencia {
  3.    
  4.     import flash.system.Capabilities;
  5.    
  6.     public class Archivo implements IArchivo{
  7.         static private var archivoImpl:IArchivo;
  8.        
  9.         /* bloque estático */
  10.         {
  11.             if( Capabilities.playerType == "Desktop" ){
  12.                 // guarda en el sistema de archivos del O.S.
  13.                 archivoImpl = new ArchivoAIR();
  14.             }else{
  15.                 // guarda en web
  16.                 archivoImpl = new ArchivoFlex();
  17.             }
  18.             trace( Capabilities.playerType );
  19.         }
  20.        
  21.         /* 
  22.          * implementacion de IArchivo
  23.          */
  24.         public function guardar():void{
  25.             archivoImpl.guardar();
  26.         }
  27.        
  28.         public function borrar():void{
  29.             archivoImpl.borrar();
  30.         }
  31.     }
  32. }
  33.  
  34. /* IArchivo.as */
  35. package com.joangarnet.persistencia{
  36.     public interface IArchivo{
  37.         function guardar():void;
  38.         function borrar():void;
  39.     }
  40. }
  41.  
  42. /* ArchivoAIR.as */
  43. package com.joangarnet.persistencia{
  44.     public class ArchivoAIR implements IArchivo{
  45.         public function guardar():void{
  46.             trace("guardar() en el sistema de archivos local")
  47.         }
  48.        
  49.         public function borrar():void{
  50.             trace("borrar() en el sistema de archivos local")
  51.         }
  52.     }
  53. }
  54.  
  55. /* ArchivoFlex.as */
  56. package com.joangarnet.persistencia{
  57.     public class ArchivoFlex implements IArchivo{
  58.         public function guardar():void{
  59.             trace("guardar() vía web")
  60.         }
  61.        
  62.         public function borrar():void{
  63.             trace("borrar() vía web")
  64.         }
  65.     }
  66. }

TestBloqueEstatico.mxml

XML:
  1. <?xml version = "1.0" encoding = "utf-8"?>
  2. <mx:Application xmlns:mx = "http://www.adobe.com/2006/mxml" layout = "absolute">
  3.     <mx:Script>
  4.         <![CDATA[
  5.             import com.joangarnet.persistencia.Archivo;
  6.  
  7.             private var f:Archivo = new Archivo();
  8.         ]]>
  9.     </mx:Script>
  10.     <mx:Button click = "f.borrar()" label="borrar" />
  11.     <mx:Button click = "f.guardar()" label="guardar" />
  12. </mx:Application>

Si se ejecuta en el contexto de una aplicación AIR y clicamos en los dos botones borrar y guardar respectivamente se mostrará en la consola:

borrar() en el sistema de archivos local
guardar() en el sistema de archivos local

Si de lo contrario se hace desde el navegador se mostrará:

borrar() vía web
guardar() vía web

Utilizando namespaces

¿Qué es?

Un namespace (espacio de nombres) es un contenedor abstracto que nos permite controlar la visibilidad de propiedades y métodos. Es algo parecido al concepto de package.
Por defecto disponemos de cuatro namespaces: private, protected, public e internal. Estos espacios de nombre tiene un comportamiento especial que permite restringir el acceso a miembros teniendo en cuenta una serie de reglas con respecto a la herencia o al package al que pertenecen.
Aparte de éstos cuatro nosotros podemos definir nuestros propios namespaces.

Un ejemplo

Definimos un namespace:

Actionscript:
  1. package com.joangarnet.namespaces{
  2.    public namespace jg_internal = "http://www.joangarnet.com/namespaces/jg_internal";
  3. }

Aplicamos el namespace a un miembro de una clase:

Actionscript:
  1. package com.joangarnet.controls{
  2.    public class Window{
  3.       import com.joangarnet.namespaces.jg_internal;
  4.       private var propiedad:String = "No soy accesible";
  5.       jg_internal var propiedad:String = "Si soy accesible";
  6.    }
  7. }

Vemos que tenemos dos propiedades "propiedad" con el mismo identificador, lo cual puede parecer erróneo. Lo que sucede al compilar es que al tener visibilidades diferentes, estan en espacios de nombres diferentes, los identificadores no colisionan.
Yo personalmente he utilizado raramente esta característica del lenguaje, pero se me ocurren algunas [pseudo]situaciones interesantes dónde puede ser útil:

Miembros pseudo privados

Hace un par de posts me quejaba del hecho que, en algún caso puntual algunas clases del SDK de Flex lo ponían dificil a la hora de proporcionar extendibilidad. La causa de ésto era la definición de miembros privados en algunas clases que entorpecían y, alguna vez incluso imposibilitaban el poder extenderlas. En un par de ocasiones he tenido que recurrir a una técnica llamada monkey patching para poder extender una clase determinada.
Una posible forma de eviar esto pasaría por definir un espacio de nombres semánticamente parecido a private (¿os suena mx_internal?) que nos permitiera extender los miembros de la clase de forma responsable, siendo conscientes de que estamos utilizando un namespace especial y que tenemos que andar con especial ojo en lo que hacemos.

Pseudo sobrecarga de métodos

El hecho que podamos definir un mismo método en diferentes espacios de nombres dentro de una misma clase nos hace recordar a la sobrecarga de métodos disponible en otros lenguajes como Java. Se puede obtener una funcionalidad parecida utilizando namespaces:

Actionscript:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="inicio()">
  3.     <mx:Script>
  4.         <![CDATA[
  5.             namespace air;
  6.             namespace flex;
  7.             private var runtime:Namespace;
  8.             private function inicio():void{
  9.                 if( Capabilities.playerType == "Desktop" ) {
  10.                     runtime = air;
  11.                 }else{
  12.                     runtime = flex
  13.                 }
  14.                 runtime::guardar();
  15.             }
  16.  
  17.             air function guardar():void {
  18.                 trace( "Guardar en filesystem" )
  19.             }
  20.  
  21.             flex function guardar():void {
  22.                 trace( "Guardar en el server" )
  23.             }
  24.         ]]>
  25.     </mx:Script>
  26. </mx:Application>

Esto ejecutado en un navegador y ejecutado en una aplicación AIR muestra dos resultados diferentes.

Ejecución pseudo condicional

La compilación condicional disponible en Flex Builder es una funcionalidad muy útil (de la que hablaré en un futuro post en madeinflex) que permite definir bloques que se ejecutan dependiendo si se ha asignado un valor determinado desde los parámetros de compilación. Esto permite por ejemplo tener rutinas de debug que solo se compilan durante el desarrollo y que en el momento de salir a producción con un simple cambio en un valor desaparecen por completo.
Con namespaces y siguiendo exactamente el mismo sistema que en el ejemplo anterior podemos hacer algo parecido como se ve en el siguiente ejemplo:

XML:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="inicio()">
  3.     <mx:Script>
  4.         <![CDATA[
  5.             namespace desarrollo;
  6.             namespace produccion;
  7.  
  8.             public static var entorno:Namespace;
  9.  
  10.             private function inicio():void{
  11.                 entorno = produccion;
  12.                 entorno::guardar();
  13.             }
  14.  
  15.             desarrollo function guardar():void {
  16.                 trace( "Estoy en desarrollo" )
  17.             }
  18.  
  19.             produccion function guardar():void {
  20.                 trace( "Estoy en producción" )
  21.             }
  22.         ]]>
  23.     </mx:Script>
  24. </mx:Application>

Enlaces relacionados

* namespace
* Namespace