Documentación de Flash CS3 |
|||
| Programación con ActionScript 3.0 > Utilización de matrices > Temas avanzados | |||
La clase Array es una de las pocas clases principales que no son finales, lo que significa que es posible crear una subclase de Array. Esta sección proporciona un ejemplo de cómo se puede crear una subclase de Array y se describen algunos de los problemas que pueden surgir durante el proceso.
Como se mencionó anteriormente, en ActionScript las matrices no tienen tipo, pero se puede crear una subclase de Array que acepte elementos de un solo tipo de datos específico. El ejemplo de las secciones siguientes define una subclase de Array denominada TypedArray que limita sus elementos a valores del tipo de datos especificado en el primer parámetro. La clase TypedArray se presenta simplemente como un ejemplo de cómo ampliar la clase Array y puede no ser adecuado para fines de producción por diversas razones. En primer lugar, la verificación de tipos se realiza en tiempo de ejecución, no en tiempo de compilación. En segundo lugar, cuando un método TypedArray encuentra un tipo no coincidente, se omite el tipo no coincidente y no se emite ninguna excepción, aunque los métodos pueden ser fácilmente modificados para emitir excepciones. Además, la clase no puede evitar el uso del operador de acceso a una matriz para insertar valores de cualquier tipo en la matriz. Por último, el estilo de programación favorece la simplicidad frente a la optimización del rendimiento.
La palabra clave extends permite indicar que una clase es una subclase de Array. Una subclase de Array debe utilizar el atributo dynamic, igual que la clase Array. De lo contrario, la subclase no funcionará correctamente.
El código siguiente muestra la definición de la clase TypedArray, que contiene una constante en la que se almacena el tipo de datos, un método constructor y los cuatro métodos que pueden añadir elementos a la matriz. En este ejemplo se omite el código de cada método, pero se describe y explica completamente en las secciones siguientes:
public dynamic class TypedArray extends Array
{
private const dataType:Class;
public function TypedArray(...args) {}
AS3 override function concat(...args):Array {}
AS3 override function push(...args):uint {}
AS3 override function splice(...args) {}
AS3 override function unshift(...args):uint {}
}
Los cuatro métodos sustituidos utilizan el espacio de nombres AS3 en lugar del atributo public, ya que en este ejemplo se supone que la opción de compilador -as3 está establecida en true y la opción de compilador -es está establecida en false. Ésta es la configuración predeterminada para Adobe Flex Builder 2 y Adobe Flash CS3 Professional. Para más información, consulte El espacio de nombres AS3.
|
SUGERENCIA |
|
Los programadores expertos que prefieren utilizar herencia de prototipo pueden hacer dos pequeños cambios en la clase TypedArray para que se compile con la opción de compilador |
El constructor de la subclase supone un reto interesante, ya que debe aceptar una lista de argumentos de longitud arbitraria. El reto consiste en pasar los argumentos al superconstructor para crear la matriz. Si se pasa la lista de argumentos en forma de matriz, el superconstructor considerará que se trata de un solo argumento de tipo Array y la matriz resultante siempre tendrá una longitud de 1 elemento. La manera tradicional de controlar las listas de argumentos es utilizar el método Function.apply(), que admite una matriz de argumentos como segundo parámetro, pero la convierte en una lista de argumentos al ejecutar la función. Por desgracia, el método Function.apply() no se puede utilizar con constructores.
La única opción que queda es volver a generar la lógica del constructor de Array in el constructor de TypedArray. El código siguiente muestra el algoritmo utilizado en el constructor de clase Array, que se puede reutilizar en el constructor de la subclase de Array:
public dynamic class Array
{
public function Array(...args)
{
var n:uint = args.length
if (n == 1 && (args[0] is Number))
{
var dlen:Number = args[0];
var ulen:uint = dlen;
if (ulen != dlen)
{
throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")");
}
length = ulen;
}
else
{
length = n;
for (var i:int=0; i < n; i++)
{
this[i] = args[i]
}
}
}
}
El constructor de TypedArray comparte la mayor parte del código del constructor de Array, con tan sólo cuatro cambios. En primer lugar, la lista de parámetros incluye un nuevo parámetro requerido de tipo Class que permite especificar el tipo de datos de la matriz. En segundo lugar, el tipo de datos pasado al constructor se asigna a la variable dataType. En tercer lugar, en la sentencia else, el valor de la propiedad length se asigna después del bucle for, de forma que length incluya únicamente argumentos del tipo adecuado. Por último, el cuerpo del bucle for utiliza la versión sustituida del método push() de forma que sólo se añadan a la matriz los argumentos que tengan el tipo de datos correcto. En el siguiente ejemplo se muestra la función constructora de TypedArray:
public dynamic class TypedArray extends Array
{
private var dataType:Class;
public function TypedArray(typeParam:Class, ...args)
{
dataType = typeParam;
var n:uint = args.length
if (n == 1 && (args[0] is Number))
{
var dlen:Number = args[0];
var ulen:uint = dlen
if (ulen != dlen)
{
throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")")
}
length = ulen;
}
else
{
for (var i:int=0; i < n; i++)
{
// verificación de tipos realizada en push()
this.push(args[i])
}
length = this.length;
}
}
}
La clase TypedArray reemplaza los cuatro métodos de la clase Array que pueden añadir elementos a una matriz. En cada caso, el método sustituido añade una verificación de tipos que evita la adición de elementos que no tienen el tipo de datos correcto. Posteriormente, cada método llama a la versión de sí mismo de la superclase.
El método push() recorre la lista de argumentos con un bucle for..in y realiza una verificación de tipos en cada argumento. Cualquier argumento que no sea del tipo correcto se quitará de la matriz args con el método splice(). Cuando el bucle for..in haya finalizado, la matriz args contendrá sólo valores de tipo dataType. A continuación, se llama a la versión de push() de la superclase con la matriz args actualizada, como se indica en el código siguiente:
AS3 override function push(...args):uint
{
for (var i:* in args)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
return (super.push.apply(this, args));
}
El método concat() crea un objeto TypedArray temporal denominado passArgs para almacenar los argumentos que superen la verificación de tipos. Esto permite reutilizar el código de verificación de tipos que existe en el método push(). Un bucle for..in recorre la matriz args y llama a push() en cada argumento. Como passArgs es de tipo TypedArray, se ejecuta la versión de push() de TypedArray. A continuación, el método concat() llama a su propia versión de la superclase, como se indica en el código siguiente:
AS3 override function concat(...args):Array
{
var passArgs:TypedArray = new TypedArray(dataType);
for (var i:* in args)
{
// verificación de tipos realizada en push()
passArgs.push(args[i]);
}
return (super.concat.apply(this, passArgs));
}
El método splice() admite una lista de argumentos arbitraria, pero los dos primeros argumentos siempre hacen referencia a un número de índice y al número de elementos que se desea eliminar. Por esta razón, el método splice() sustituido sólo hace la verificación de tipos para los elementos de la matriz args cuya posición de índice sea 2 o superior. Un aspecto interesante del código es que parece una llamada recursiva a splice() desde el bucle for, pero no es una llamada recursiva, ya que args es de tipo Array, no TypedArray, lo que significa que la llamada a args.splice() es una llamada a la versión del método de la superclase. Cuando el bucle for..in haya finalizado, la matriz args sólo contendrá valores del tipo correcto en posiciones cuyo índice sea 2 o superior, y splice() llamará a su propia versión de la superclase, como se indica en el código siguiente:
AS3 override function splice(...args):*
{
if (args.length > 2)
{
for (var i:int=2; i< args.length; i++)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
}
return (super.splice.apply(this, args));
}
El método unshift(), que añade elementos al principio de una matriz, también acepta una lista de argumentos arbitraria. El método unshift() sustituido utiliza un algoritmo muy similar al utilizado por el métodopush(), como se indica en el siguiente ejemplo código:
AS3 override function unshift(...args):uint
{
for (var i:* in args)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
return (super.unshift.apply(this, args));
}
}
Flash CS3
Enviarme un mensaje de correo electrónico cuando se añadan comentarios a esta página | Informe de comentarios
Página actual: http://livedocs.adobe.com/flash/9.0_es/main/00000093.html