Buscar:

viernes, 4 de marzo de 2011

Programación Orientada a Objetos con ActionScript [1ª Parte]

En este capítulo se describen los elementos de ActionScript que admiten la programación orientada a objetos. No se describen principios generales de la programación orientada a objetos, como el diseño de objetos, la abstracción, la encapsulación, la herencia y el polimorfismo. El capítulo se centra en la manera de aplicar estos principios con ActionScript 3.0.Como ActionScript fue originalmente un lenguaje de creación de scripts, en ActionScript 3.0 la compatibilidad con la programación orientada a objetos es opcional. Esto proporciona a los programadores la flexibilidad de elegir el mejor enfoque para proyectos de ámbito y complejidad variables. Para tareas pequeñas, es posible que sea suficiente con utilizar un paradigma de programación mediante procedimientos. Para proyectos más grandes, los principios de la
programación orientada a objetos pueden facilitar la comprensión, el mantenimiento y la ampliación del código.

Fundamentos de la programación orientada a objetos

Introducción a la programación orientada a objetos:
La programación orientada a objetos es una forma de organizar el código de un programa agrupándolo en objetos, que son elementos individuales que contienen información (valores de datos) y funcionalidad. La utilización de un enfoque orientado a objetos para organizar un programa permite agrupar partes específicas de la información (por ejemplo, información de una canción como el título de álbum, el título de la pista o el nombre del artista) junto con funcionalidad o acciones comunes asociadas con dicha información (como "añadir pista a la lista de reproducción" o "reproducir todas las canciones de este artista"). Estos elementos se combinan en un solo elemento, denominado objeto (por ejemplo, un objeto "Album" o "MusicTrack"). Poder agrupar estos valores y funciones proporciona varias ventajas, como la
capacidad de hacer un seguimiento de una sola variable en lugar de tener que controlar varias variables, agrupar funcionalidad relacionada y poder estructurar programas de maneras que reflejen mejor el mundo real.

Tareas comunes de la programación orientada a objetos:

En la práctica, la programación orientada a objetos consta de dos partes. Por un lado, las estrategias y técnicas para diseñar un programa (diseño orientado a objetos). Esto es un tema amplio que no se tratará en este capítulo. El otro aspecto de la programación orientada a objetos son las estructuras de programación que están disponibles en un lenguaje de programación determinado para crear un programa con un enfoque orientado a objetos. En este capítulo se describen las siguientes tareas comunes de la programación orientada a objetos:

  • Definición de clases
  • Crear propiedades, métodos y descriptores de acceso get y set (métodos descriptores de acceso)
  • Controlar el acceso a clases, propiedades, métodos y descriptores de acceso
  • Crear propiedades y métodos estáticos
  • Crear estructuras de tipo enumeración
  • Definir y utilizar interfaces
  • Trabajo con herencia, incluida la sustitución de elementos de clase
Conceptos y términos importantes:
La siguiente lista de referencia contiene términos importantes que se utilizan en este capítulo:
  • Atributo: característica asignada a un elemento de clase (como una propiedad o un método) en la definición de clase. Los atributos se suelen utilizar para definir si la propiedad o el método serán accesibles para el código de otras partes del programa. Por ejemplo, private y public son atributos. Sólo se puede llamar a un método privado desde dentro de la clase; en cambio, se puede llamar a un método público desde cualquier parte del programa.
  • Clase: definición de la estructura y el comportamiento de objetos de un tipo determinado (como una plantilla o un plano de los objetos de ese tipo de datos).
  • Jerarquía de clases: estructura de varias clases relacionadas, que especifica qué clases heredan funcionalidad de otras clases.
  • Constructor: método especial que se puede definir en una clase y que se llama para crear una instancia de la clase.
  • Se suele utilizar un constructor para especificar valores predeterminados o realizar operaciones de configuración del objeto.
  • Tipo de datos: tipo de información que una variable concreta puede almacenar. En general, tipo de datos significa lo mismo que clase.
  • Operador punto: signo del punto (.), que en ActionScript y en muchos otros lenguajes de programación se utiliza para indicar que un nombre hace referencia a un elemento secundario de un objeto (como una propiedad o un método). Por ejemplo, en la expresión:
    myObjeto.myPropiedad
    , el operador punto indica que el término myPropiedad hace referencia a algún valor que es un elemento del objeto denominado myObjeto.
  • Enumeración: conjunto de valores de constante relacionados, agrupados por comodidad como propiedades de una clase individual.
  • Herencia: mecanismo de la programación orientada a objetos que permite a una definición de clase incluir toda la funcionalidad de una definición de clase distinta (y añadir nueva funcionalidad).
  • Instancia: objeto real creado en un programa.
  • Espacio de nombres: fundamentalmente se trata de un atributo personalizado que ofrece un control más preciso sobre el código al que puede acceder otro código.

Ejecución de los ejemplos del capítulo:
A medida que progresa en el estudio del capítulo, es posible que desee probar algunos de los listados de código. Como los listados de código de este capítulo se centran principalmente en definir y manipular tipos de datos, para probar los ejemplos hay que crear una instancia de la clase que se está definiendo, manipular esa instancia con sus propiedades o métodos y, a continuación, ver los valores de las propiedades de la instancia. Para ver esos valores hay que escribir valores en una instancia de campo de texto del escenario o utilizar la función trace() para imprimir valores en el panel Salida.
Clases
Una clase es una representación abstracta de un objeto. Una clase almacena información sobre los tipos de datos que un objeto puede contener y los comportamientos que un objeto puede exhibir. La utilidad de esta abstracción puede no ser apreciable al escribir scripts sencillos que sólo contienen unos pocos objetos que interactúan entre sí. Sin embargo, a medida que el ámbito de un programa crece y aumenta el número de objetos que hay que administrar, las clases pueden ayudar a obtener mayor control sobre la creación y la interacción mutua de los objetos.

Con ActionScript 1.0 los programadores podían utilizar objetos Function para crear construcciones similares a las clases. ActionScript 2.0 añadió formalmente la compatibilidad con las clases con palabras clave como class y extends. En ActionScript 3.0 no sólo se mantienen las palabras clave introducidas en ActionScript 2.0, sino que también se han añadido algunas capacidades nuevas, como el control de acceso mejorado con los atributos protected e internal, y mejor control de la herencia con las palabras clave final y override.
A los programadores con experiencia en la creación de clases con lenguajes de programación como Java, C++ o C#, el sistema de objetos de ActionScript les resultará familiar. ActionScript comparte muchas de las mismas palabras clave y nombres de atributo, como class, extends y public, que se describen en las siguiente secciones.

Nota: en este capítulo, el término propiedad designa cualquier miembro de un objeto o una clase, incluidas variables, constantes y métodos. Por otra parte, aunque los términos class y static se suelen utilizar como sinónimos, en este capítulo tienen un significado diferente. Por ejemplo, en este capítulo la frase propiedades de clase hace referencia a todos los miembros de una clase, no únicamente a los miembros estáticos.
Definiciones de clase:
En las definiciones de clase de ActionScript 3.0 se utiliza una sintaxis similar a la utilizada en las definiciones de clase de ActionScript 2.0. La sintaxis correcta de una definición de clase requiere la palabra clave class seguida del nombre de la clase. El cuerpo de la clase, que se escribe entre llaves ({}), sigue al nombre de la clase. Por ejemplo, el código siguiente crea una clase denominada Forma que contiene una variable denominada visible:

public class Forma
{
    var visible:Boolean = true;
}
 
Un cambio de sintaxis importante afecta a las definiciones de clase que están dentro de un paquete. En ActionScript 2.0, si una clase estaba dentro de un paquete, había que incluir el nombre de paquete en la declaración de la clase. En ActionScript 3.0 se incluye la sentencia package y hay que incluir el nombre del paquete en la declaración del paquete, no en la declaración de clase. Por ejemplo, las siguientes declaraciones de clase muestran la manera de definir la clase BitmapData, que forma parte del paquete flash.display, en ActionScript 2.0 y en ActionScript 3.0:

// ActionScript 2.0
class flash.display.BitmapData {}


// ActionScript 3.0
package flash.display
{
    public class BitmapData {}
}


Atributos de clase:
ActionScript 3.0 permite modificar las definiciones de clase mediante uno de los cuatro atributos siguientes:

Todos estos atributos, salvo internal, deben ser incluidos explícitamente para obtener el comportamiento asociado.
Por ejemplo, si no se incluye el atributo dynamic al definir una clase, no se podrá añadir propiedades a una instancia de clase en tiempo de ejecución. Un atributo se asigna explícitamente colocándolo al principio de la definición de clase, como se muestra en el código siguiente:

dynamic class Forma {}

Hay que tener en cuenta que la lista no incluye un atributo denominado abstract. Esto se debe a que las clases abstractas no se admiten en ActionScript 3.0. También se debe tener en cuenta que la lista no incluye atributos denominados private y protected. Estos atributos sólo tienen significado dentro de una definición de clase y no se pueden aplicar a las mismas clases. Si no se desea que una clase sea visible públicamente fuera de un paquete, debe
colocarse la clase dentro de un paquete y marcarse con el atributo internal. Como alternativa, se pueden omitir los atributos internal y public, y el compilador añadirá automáticamente el atributo internal. Si no se desea que una clase sea visible fuera del archivo de código fuente en el que está definida, se debe colocar al final del archivo de
código fuente después de la llave final de la definición de paquete.

Cuerpo de la clase:
El cuerpo de la clase, que se escribe entre llaves, se usa para definir las variables, constantes y métodos de la clase. En el siguiente ejemplo se muestra la declaración para la clase Accessibility en la API de Adobe Flash Player:

public final class Accessibility
{
    public static function get Activo():Boolean;
    public static function ActualizaPropiedad():void;
}

También se puede definir un espacio de nombres dentro de un cuerpo de clase. En el siguiente ejemplo se muestra cómo se puede definir un espacio de nombres en el cuerpo de una clase y utilizarse como atributo de un método en dicha clase:

public class EjemploClase
{
    public namespace EjEspacioNombre;
    EjEspacioNombre function HacerAlgo():void;
}


ActionScript 3.0 permite incluir en el cuerpo de una clase no sólo definiciones, sino también sentencias. Las sentencias que están dentro de un cuerpo de clase pero fuera de una definición de método se ejecutan una sola vez: cuando se encuentra por primera vez la definición de la clase y se crea el objeto de clase asociado. En el ejemplo siguiente se incluye una llamada a una función externa, Hola(), y una sentencia trace que emite un mensaje de confirmación
cuando se define la clase:

function Hola():String
{
    trace("hola");
}
class EjemploClase
{
    Hola();
    trace("Clase Creada");
}
//Salida cuando la clase se crea
//hola
//Clase Creada

A diferencia de las versiones anteriores de ActionScript, en ActionScript 3.0 se permite definir en un mismo cuerpo de clase una propiedad estática y una propiedad de instancia con el mismo nombre. Por ejemplo, el código siguiente declara una variable estática denominada Mensaje y una variable de instancia con el mismo nombre:

class PruebaEstatica
{
    static var Mensaje:String = "Variable Estática";
    var Mensaje:String = "Variable de Instancia";
}
// En el Script
var myPE:PruebaEstatica = new PruebaEstatica();
trace(PruebaEstatica.Mensaje); // Salida: Variable Estatica
trace(myPE.Mensaje); // Salida: Varieble de Instancia

Atributos de propiedad de clase:
En las descripciones del modelo de objetos de ActionScript, el término propiedad significa cualquier cosa que pueda ser un miembro de una clase, incluidas variables, constantes y métodos. Esto difiere de la manera en que se utiliza el término en la Referencia del lenguaje y componentes ActionScript 3.0, donde se aplica a un concepto menos amplio y sólo incluye miembros de clase que son variables o se definen mediante un método captador o definidor. En ActionScript 3.0 hay un conjunto de atributos que se pueden utilizar con cualquier propiedad de una clase. En la tabla siguiente se muestra este conjunto de atributos.

Atributos del espacio de nombres de control de acceso:
ActionScript 3.0 proporciona cuatro atributos especiales que controlan el acceso a las propiedades definidas dentro de una clase: public, private, protected e internal.
El atributo public hace que una propiedad esté visible en cualquier parte del script. Por ejemplo, para hacer que un método esté disponible para el código fuera de su paquete, hay que declarar el método con el atributo public. Esto se cumple para cualquier propiedad, independientemente de que se declare con la palabra clave var, const o function.

El atributo private hace que una propiedad sólo esté visible para los orígenes de llamada de la clase en la que se define la propiedad. Este comportamiento difiere del comportamiento del atributo private en ActionScript 2.0, que permitía a una subclase tener acceso a una propiedad privada de una superclase. Otro cambio importante de comportamiento está relacionado con el acceso en tiempo de ejecución. En ActionScript 2.0, la palabra clave private sólo prohibía el acceso en tiempo de compilación y se podía evitar fácilmente en tiempo de ejecución. Esto ya no se cumple en ActionScript 3.0. Las propiedades marcadas como private no están disponibles en tiempo de compilación ni en tiempo de ejecución.

Por ejemplo, el código siguiente crea una clase simple denominada PrivateEjemplo con una variable privada y después intenta acceder a la variable privada desde fuera de la clase. En ActionScript 2.0, el acceso en tiempo de compilación estaba prohibido, pero la prohibición se podía evitar fácilmente utilizando el operador de acceso a una propiedad ([]), que realiza la búsqueda de propiedades en tiempo de ejecución, no en tiempo de compilación.

class EjemploPrivado
{
    private var privVar:String = "Variable Privada";
}


var miEjemplo:EjemploPrivado = new EjemploPrivado();
trace(
miEjemplo.privVar);// Error en modo estricto en tiempo de ejecucion
trace(
miEjemplo["privVar"]); /* ActionScript 2.0 permite el acceso, pero en ActionScript 3.0, esta es un error en tiempo de ejecucion */

En ActionScript 3.0, un intento de acceder a una propiedad privada mediante el operador punto (miEjemplo.privVar) provoca un error de tiempo de compilación si se utiliza el modo estricto. De lo contrario, el error se notifica en tiempo de ejecución, de la misma manera que al usar el operador de acceso a una propiedad (miEjemplo["privVar"]).

En la tabla siguiente se resumen los resultados de intentar acceder a una propiedad privada que pertenece a una clase cerrada (no dinámica):




En clases declaradas con el atributo dynamic, los intentos de acceder a una variable privada no provocarán un error en tiempo de ejecución. La variable simplemente no está visible, por lo que Flash Player o Adobe® AIR™ devuelven el valor undefined. No obstante, se producirá un error en tiempo de compilación si se utiliza el operador punto en modo estricto. El ejemplo siguiente es igual que el anterior, con la diferencia de que la clase Ejmeplo Privado se declara como una clase dinámica:

dynamic class EjemploPrivado
{
    private var privVar:String = "Variable Privada";
}
var miEjemplo:EjemploPrivado = new EjemploPrivado();
trace(miEjemplo.privVar);//Error en modo estricto, en tiempo de ejecucion
trace(miEjemplo["privVar"]); // Salida: undefined

Las clases dinámicas generalmente devuelven el valor undefined en lugar de generar un error cuando código externo a una clase intenta acceder a una propiedad privada. En la tabla siguiente se muestra que sólo se genera un error cuando se utiliza el operador punto para acceder a una propiedad privada en modo estricto:

El atributo protected, que es una de las novedades de ActionScript 3.0, hace que una propiedad esté visible para los orígenes de llamada en su propia clase o en una subclase. Es decir, una propiedad protegida está disponible en su propia clase o para clases de nivel inferior en la jerarquía de herencia. Esto se cumple tanto si la subclase está en el mismo paquete como si está en un paquete diferente.

Para los usuarios familiarizados con ActionScript 2.0, esta funcionalidad es similar al atributo private en ActionScript 2.0. El atributo protected de ActionScript 3.0 también es similar al atributo protected en Java, pero difiere en que la versión de Java también permite acceder a quien realiza la llamada en el mismo paquete. El atributo protected resulta útil cuando se tiene una variable o método requerido por las subclases que se desea ocultar del código que esté fuera de la cadena de herencia.

El atributo internal, que es una de las novedades de ActionScript 3.0, hace que una propiedad esté visible para los orígenes de llamada en su propio paquete. Es el atributo predeterminado para el código de un paquete y se aplica a cualquier propiedad que no tenga ninguno de los siguientes atributos:
  • public
  • private
  • protected
  • un espacio de nombres definido por el usuario
El atributo internal es similar al control de acceso predeterminado en Java, aunque en Java no hay ningún nombre explícito para este nivel de acceso y sólo se puede alcanzar mediante la omisión de cualquier otro modificador de acceso. El atributo internal está disponible en ActionScript 3.0 para ofrecer la opción de indicar explícitamente la intención de hacer que una propiedad sólo sea visible para orígenes de llamada de su propio paquete.

Atributo static:
El atributo static, que se puede utilizar con propiedades declaradas con las palabras clave var, const o function, permite asociar una propiedad a la clase en lugar de asociarla a instancias de la clase. El código externo a la clase debe llamar a propiedades estáticas utilizando el nombre de la clase en lugar de un nombre de instancia.
Las subclases no heredan las propiedades estáticas, pero las propiedades forman parte de una cadena de ámbitos de subclase. Esto significa que en el cuerpo de una subclase se puede utilizar una variable o un método estático sin hacer referencia a la clase en la que se definió.

Atributos de espacio de nombres definido por el usuario:
Como alternativa a los atributos de control de acceso predefinidos se puede crear un espacio de nombres personalizado para usarlo como un atributo. Sólo se puede utilizar un atributo de espacio de nombres por cada definición y no se puede utilizar en combinación con uno de los atributos de control de acceso (public, private, protected, internal).

Variables:
Las variables pueden declararse con las palabras clave var o const. Es posible cambiar los valores de las variables declaradas con la palabra clave var varias veces durante la ejecución de un script. Las variables declaradas con la palabra clave const se denominan constantes y se les puede asignar valores una sola vez. Un intento de asignar un valor nuevo a una constante inicializada provoca un error.

Variables estáticas:
Las variables estáticas se declaran mediante una combinación de la palabra clave static y la sentencia var o const.
Las variables estáticas, que se asocian a una clase en lugar de a una instancia de una clase, son útiles para almacenar y compartir información que se aplica a toda una clase de objetos. Por ejemplo, una variable estática es adecuada si se desea almacenar un recuento del número de veces que se crea una instancia de una clase o si se desea almacenar el número máximo de instancias de la clase permitidas.

En el ejemplo siguiente se crea una variable totalContador para hacer un seguimiento del número de instancias de clase creadas y una constante MAX_NUM para almacenar el número máximo de instancias creadas. Las variables totalContador y MAX_NUM son estáticas porque contienen valores que se aplican a la clase como un todo en lugar de a una instancia concreta.

class VarEstatico
{
    public static var totalContador:int = 0;
    public static const MAX_NUM:uint = 16;
}


El código externo a la clase VarEstatico y a cualquiera de sus subclases sólo puede hacer referencia a las propiedades totalContador y MAX_NUM a través de la misma clase. Por ejemplo, el siguiente código funciona:

trace(VarEstatico.totalContador); // Salida: 0
trace(VarEstatico.MAX_NUM); // Salida: 16


No se puede acceder a variables estáticas a través de una instancia de la clase, por lo que el código siguiente devuelve errores:

var miVarEstatico:VarEstatico = new VarEstatico();
trace(
miVarEstatico.totalContador); // error
trace(
miVarEstatico.MAX_NUM); // error

Las variables declaradas con las palabras clave static y const deben ser inicializadas a la vez que se declara la constante, como hace la clase VarEstatico para MAX_NUM. No se puede asignar un valor a MAX_NUM dentro del constructor o de un método de instancia. El código siguiente generará un error, ya que no es una forma válida de inicializar una constante estática:

// !! Error al inicializar constante estática de esta manera
class VarEstatico2
{
    public static const TIPO_UNICO:uint;
    function InicializaEstatico():void
    {
       
TIPO_UNICO = 16;
    }
}

Variables de instancia:
Las variables de instancia incluyen propiedades declaradas con las palabras clave var y const, pero sin la palabra clave static. Las variables de este tipo, que se asocian a instancias de clase en lugar de a una clase completa, son útiles para almacenar valores específicos de una instancia. Por ejemplo, la clase Array tiene una propiedad de instancia denominada length que almacena el número de elementos de conjunto contenidos en una instancia concreta de la
clase Array.

En una subclase no se pueden sustituir las variables de instancia, aunque se declaren como var o const. Sin embargo, se puede obtener una funcionalidad similar a la sustitución de variables sustituyendo métodos de captador y definidor.

Métodos:
Los métodos son funciones que forman parte de una definición de clase. Cuando se crea una instancia de la clase, se vincula un método a esa instancia. A diferencia de una función declarada fuera de una clase, un método sólo puede utilizarse desde la instancia a la que está asociado.

Los métodos se definen con la palabra clave function. Al igual que sucede con cualquier propiedad de clase, puede aplicar cualquiera de sus atributos a los métodos, incluyendo private, protected, public, internal, static o un espacio de nombres personalizado. Puede utilizar una sentencia de función como la siguiente:

public function EjemploFuncion():String {}

También se puede utilizar una variable a la que se asigna una expresión de función, de la manera siguiente:

public var EjemploFuncion:Function = function () {}

En la mayoría de los casos se deseará utilizar una sentencia de función en lugar de una expresión de función por las siguientes razones:

  • Las sentencias de función son más concisas y fáciles de leer.
  • Permiten utilizar las palabras clave override y final.
  • Crean un vínculo más fuerte entre el identificador (es decir, el nombre de la función) y el código del cuerpo del método. Como es posible cambiar el valor de una variable con una sentencia de asignación, la conexión entre una variable y su expresión de función se puede hacer más fuerte en cualquier momento. Aunque se puede solucionar este problema declarando la variable con const en lugar de var, esta técnica no se considera una práctica recomendable, ya que hace que el código sea difícil de leer e impide el uso de las palabras clave override y final.
Un caso en el que hay que utilizar una expresión de función es cuando se elige asociar una función al objeto prototipo.

Métodos constructores:
Los métodos constructores, que a veces se llaman simplemente constructores, son funciones que comparten el nombre con la clase en la que se definen. Todo el código que se incluya en un método constructor se ejecutará siempre que una instancia de la clase se cree con la palabra clave new. Por ejemplo, el código siguiente define una clase simple denominada Ejemplo que contiene una sola propiedad denominada Estado. El valor inicial de la variable Estado se
establece en la función constructora.

class Ejemplo
{

    public var Estado:String;
    public function Ejemplo()
    {
        Estado = "Inicializado";
    }
}
var miEjemplo:Ejemplo = new Ejemplo();
trace(miEjemplo.Estado); // Salida: Inicializado


Los métodos constructores sólo pueden ser públicos, pero el uso del atributo public es opcional. No se puede utilizar en un constructor ninguno de los otros especificadores de control de acceso, incluidos private, protected e internal . Tampoco se puede utilizar un espacio de nombres definido por el usuario con un método constructor.

Un constructor puede hacer una llamada explícita al constructor de su superclase directa utilizando la sentencia super(). Si no se llama explícitamente al constructor de la superclase, el compilador inserta automáticamente una llamada antes de la primera sentencia en el cuerpo del constructor. También se puede llamar a métodos de la superclase mediante el prefijo super como una referencia a la superclase. Si se decide utilizar super() y super en el mismo cuerpo de constructor, hay que asegurarse de llamar primero a super(). De lo contrario, la referencia super no se comportará de la manera esperada. También se debe llamar al constructor super() antes que a cualquier sentencia throw o return.

En el ejemplo siguiente se ilustra lo que sucede si se intenta utilizar la referencia super antes de llamar al constructor super(). Una nueva clase, EjemploEx, amplía la clase Ejemplo. El constructor de EjemploEx intenta acceder a la variable de estado definida en su superclase, pero lo hace antes de llamar a super(). La sentencia trace() del constructor de EjemploEx produce el valor null porque la variable Estado no está disponible hasta que se ejecuta el
constructor super().

class EjemploEx extends Ejemplo
{
    public function EjemploEx()
    {
        trace(super.Estado);
        super();
    }
}
var miEjemploEx:EjemploEx = new EjemploEx(); //Salida: Null


Aunque se puede utilizar la sentencia return dentro de un constructor, no se permite devolver un valor. Es decir, las sentencias return no deben tener expresiones o valores asociados. Por consiguiente, no se permite que los métodos constructores devuelvan valores, lo que significa que no se puede especificar ningún tipo de devolución.

Si no se define un método constructor en la clase, el compilador creará automáticamente un constructor vacío. Si la clase amplía otra clase, el compilador incluirá una llamada super() en el constructor que genera.

Métodos estáticos:
Los métodos estáticos, también denominados métodos de clase, son métodos que se declaran con la palabra clave static. Estos métodos, que se asocian a una clase en lugar de a una instancia de clase, son útiles para encapsular la funcionalidad que afecta a algo más que el estado de una instancia individual. Como los métodos estáticos se asocian a una clase como un todo, sólo se puede acceder a dichos métodos a través de una clase, no a través de una instancia de la clase.

Los métodos estáticos son útiles para encapsular la funcionalidad que no se limita a afectar al estado de las instancias de clase. Es decir, un método debe ser estático si proporciona funcionalidad que no afecta directamente al valor de una instancia de clase. Por ejemplo, la clase Date tiene un método estático denominado parse(), que convierte una cadena
en un número. El método es estático porque no afecta a una instancia individual de la clase. El método parse() recibe una cadena que representa un valor de fecha, analiza la cadena y devuelve un número con un formato compatible con la representación interna de un objeto Date. Este método no es un método de instancia porque no tiene sentido aplicar el método a una instancia de la clase Date.

El método parse() estático puede compararse con uno de los métodos de instancia de la clase Date, como getMonth(). El método getMonth() es un método de instancia porque opera directamente en el valor de una instancia recuperando un componente específico, el mes, de una instancia de Date.

Como los métodos estáticos no están vinculados a instancias individuales, no se pueden utilizar las palabras clave this o super en el cuerpo de un método estático. Las referencias this y super sólo tienen sentido en el contexto de un método de instancia.

En contraste con otros lenguajes de programación basados en clases, en ActionScript 3.0 los métodos estáticos no se heredan.

Métodos de instancia:
Los métodos de instancia son métodos que se declaran sin la palabra clave static. Estos métodos, que se asocian a instancias de una clase en lugar de a la clase como un todo, son útiles para implementar funcionalidad que afecta a instancias individuales de una clase. Por ejemplo, la clase Array contiene un método de instancia denominado sort(), que opera directamente en instancias de Array.

En el cuerpo de un método de instancia, las variables estáticas y de instancia están dentro del ámbito, lo que significa que se puede hacer referencia a las variables definidas en la misma clase mediante un identificador simple. Por ejemplo, la clase siguiente, CustomArray, amplía la clase Array. La clase CustomArray define una variable estática denominada arrayContaTotal para hacer un seguimiento del número total de instancias de clase, una variable de instancia denominada arrayNumero que hace un seguimiento del orden en que se crearon las instancias y un método de instancia denominado getPosicion() que devuelve los valores de estas variables.

public class CustomArray extends Array
{
    public static var arrayContTotal:int = 0;

   
public var arrayNumero:int;

   
public function CustomArray()
    {
        arrayNumber = ++arrayContTotal;
    }

    public function getPosicion():String
    {
        return ("Array " + arrayNumber + " de " + arrayCountTotal);
    }
}


Aunque el código externo a la clase debe hacer referencia a la variable estática arrayContTotal a través del objeto de clase mediante CustomArray.arrayContTotal, el código que reside dentro del cuerpo del método getPosicion() puede hacer referencia directamente a la variable estática arrayContTotal. Esto se cumple incluso para variables estáticas de superclases. Aunque en ActionScript 3.0 las propiedades estáticas no se heredan, las propiedades estáticas de las superclases están dentro del ámbito. Por ejemplo, la clase Array tiene unas pocas variables estáticas, una de las cuales es una constante denominada DESCENDING. El código que reside en una subclase de Array puede hacer referencia a la constante estática DESCENDING mediante un identificador simple:

public class CustomArray extends Array
{
    public function PruebaEstatica():void
    {
        trace(DESCENDING); // Salida: 2
    }
}


El valor de la referencia this en el cuerpo de un método de instancia es una referencia a la instancia a la que está asociado el método. El código siguiente muestra que la referencia this señala a la instancia que contiene el método:

class ThisPrueba
{
    function thisValor():ThisPrueba
    {
        return this;
    }
}


var miPrueba:ThisPrueba = new ThisPrueba();
trace(miPrueba.thisValor() == miPrueba); // Salida: true


La herencia de los métodos de instancia se puede controlar con las palabras clave override y final. Se puede utilizar el atributo override para redefinir un método heredado y el atributo final para evitar que las subclases sustituyan un método.

Métodos descriptores de acceso (captador y definidor):
Las funciones descriptoras de acceso get y set, también denominadas captadores y definidores, permiten implementar los principios de programación relacionados con la ocultación de información y encapsulación a la vez que ofrecen una interfaz de programación fácil de usar para las clases que se crean. Estas funciones permiten mantener las propiedades de clase como privadas de la clase ofreciendo a los usuarios de la clase acceso a esas propiedades como si accedieran a una variable de clase en lugar de llamar a un método de clase.

La ventaja de este enfoque es que permite evitar las funciones descriptoras de acceso tradicionales con nombres poco flexibles, como getPropertyName() y setPropertyName(). Otra ventaja de los captadores y definidores es que permiten evitar tener dos funciones públicas por cada propiedad que permita un acceso de lectura y escritura.
La siguiente clase de ejemplo, denominada GetSet, incluye funciones descriptoras de acceso get y set denominadas publicAcceso() que proporcionan acceso a la variable privada denominada PropiedadPrivada:

class GetSet
{
    private var PropiedadPrivada:String;

    public function get publicAcceso():String
    {
        return PropiedadPrivada;
    }

    public function set publicAcceso(setValor:String):void
    {
        PropiedadPrivada = setValor;
    }
}


Si se intenta directamente acceder a la propiedad PropiedadPrivada se producirá un error, como se muestra a continuación:

var miGetSet:GetSet = new GetSet();
trace(miGetSet.PropiedadPrivada); // Error


En su lugar, un usuario de la clase GetSet utilizará algo que parece ser una propiedad denominada publicAcceso, pero que en realidad es un par de funciones descriptoras de acceso get y set que operan en la propiedad privada denominada PropiedadPrivada. En el ejemplo siguiente se crea una instancia de la clase GetSet y después se establece el valor de
PropiedadPrivada mediante el descriptor de acceso público denominado publicAcceso:

var miGetSet:GetSet = new GetSet();
trace(miGetSet.publicAcceso); // resultado: null
miGetSet.publicAcceso = "Hola";
trace(myGetSet.publicAccess); // resultado: Hola


Las funciones captadoras y definidoras también permiten sustituir propiedades heredadas de una superclase, algo que no es posible al usar variables miembro de clase normales. Las variables miembro de clase que se declaran mediante la palabra clave var no se pueden sustituir en una subclase. Sin embargo, las propiedades que se crean mediante funciones captadoras y definidoras no tienen esta restricción. Se puede utilizar el atributo override en funciones captadoras y definidoras heredadas de una superclase.

Métodos vinculados:
Un método vinculado, a veces denominado cierre de método, es simplemente un método que se extrae de su instancia.
Los métodos que se pasan como argumentos a una función o se devuelven como valores desde una función son ejemplos de métodos vinculados. Una de las novedades de ActionScript 3.0 es que un método vinculado es similar a un cierre de función, ya que conserva su entorno léxico incluso cuando se extrae de su instancia. Sin embargo, la diferencia clave entre un método vinculado y un cierre de función es que la referencia this para un método vinculado permanece vinculada a la instancia que implementa el método. Es decir, la referencia this de un método vinculado siempre señala al objeto original que implementó el método. Para los cierres de función, la referencia this es genérica, lo que significa que señala al objeto con el que esté relacionada la función cuando se invoque.

Es importante comprender los métodos vinculados para utilizar la palabra clave this. Debe recordarse que la palabra clave this proporciona una referencia al objeto principal de un método. La mayoría de los programadores que utilizan ActionScript esperan que la palabra clave this siempre haga referencia al objeto o la clase que contiene la definición de un método. Sin embargo, sin la vinculación de métodos esto no se cumplirá siempre. Por ejemplo, en las versiones anteriores de ActionScript, la referencia this no siempre hacía referencia a la instancia que implementaba el método.

En ActionScript 2.0, cuando se extraen métodos de una instancia no sólo no se vincula la referencia this a la instancia original, sino que además las variables y los métodos miembro de la clase de la instancia no están disponibles. Esto es no un problema en ActionScript 3.0 porque se crean métodos vinculados automáticamente cuando se pasa un método como parámetro. Los métodos vinculados garantizan que la palabra clave this siempre haga referencia al objeto o la clase en que se define un método.

El código siguiente define una clase denominada ThisPrueba, que contiene un método denominado foo() que define el método vinculado y un método denominado bar() que devuelve el método vinculado. El código externo a la clase crea una instancia de la clase ThisPrueba, llama al método bar() y almacena el valor devuelto en una variable denominada miFunc.

class ThisPrueba
{
    private var num:Number = 3;
    function foo():void // método vinculado definido
    {
        trace("foo es esto:
" + this);
        trace("num: " + num);
    }
    function bar():Function    {        return foo; // método vinculado devuelto
    }
}
var miPrueba:ThisPrueba = new ThisPrueba();
var miFunc:Function = miPrueba.bar();
trace(this); // salida: [objeto global]
miFunc();
/* salida:
foo es esto: [objeto ThisPrueba]
salida: num: 3*/


Las dos últimas líneas de código muestran que la referencia this del método vinculado foo() sigue señalando a una instancia de la clase ThisPrueba, aunque la referencia this de la línea inmediatamente anterior señala al objeto global.

Además, el método vinculado almacenado en la variable miFunc sigue teniendo acceso a las variables miembro de la clase ThisPrueba. Si se ejecutara este mismo código en ActionScript 2.0, las referencias this coincidirían y el valor de la variable num sería undefined.
La adición de métodos vinculados se aprecia mejor en aspectos como los controladores de eventos, ya que el método addEventListener() requiere que se pase una función o un método como un argumento.


Enumeraciones con clases:
Las enumeraciones son tipos de datos personalizados que se crean para encapsular un pequeño conjunto de valores.
ActionScript 3.0 no ofrece una capacidad de enumeración específica, a diferencia de C++, que incluye la palabra clave enum, o Java, con su interfaz Enumeration. No obstante, se pueden crear enumeraciones utilizando clases y constantes estáticas. Por ejemplo, la clase PrintJob en ActionScript 3.0 utiliza una enumeración denominada PrintJobOrientation
para almacenar el conjunto de valores formado por "landscape" y "portrait", como se muestra en el código siguiente:


public final class PrintJobOrientation
{
    public static const PAISAJE:String = "Paisaje";
    public static const RETRATO:String = "Retrato";
}

Por convención, una clase de enumeración se declara con el atributo final porque no es necesario ampliarla. La clase sólo contiene miembros estáticos, lo que significa que no se crean instancias de la clase, sino que se accede a los valores de la enumeración directamente a través del objeto de clase, como se indica en el siguiente fragmento de código:


var pj:PrintJob = new PrintJob();
if(pj.start())
{
    if (pj.orientation == PrintJobOrientation.RETRATO)
    {
        ...
    }
    ...
}


Todas las clases de enumeración en ActionScript 3.0 sólo contienen variables de tipo String, int o uint. La ventaja de utilizar enumeraciones en lugar de valores literales numéricos o de cadena es que es más fácil detectar errores tipográficos con las enumeraciones. Si se escribe incorrectamente el nombre de una enumeración, el compilador de ActionScript genera un error. Si se utilizan valores literales, el compilador no mostrará ninguna advertencia en caso
de que encuentre una palabra escrita incorrectamente o se utilice un número incorrecto. En el ejemplo anterior, el compilador genera un error si el nombre de la constante de enumeración es incorrecto, como se indica en el siguiente fragmento:

if (pj.orientation == PrintJobOrientation.RETRATO) // Error de compilacion


Sin embargo, el compilador no generará un error si se escribe incorrectamente un valor literal de cadena, como se muestra a continuación:

if (pj.orientation == "Retratoi") // Sin error de Compilacion

Otra técnica para crear enumeraciones también implica crear una clase independiente con propiedades estáticas para la enumeración. No obstante, esta técnica difiere en que cada una de las propiedades estáticas contiene una instancia de la clase en lugar de una cadena o un valor entero. Por ejemplo, el código siguiente crea una clase de enumeración para los días de la semana:
 


public final class Día
{
public static const LUNES:
Día= new Día();
public static const MARTES:
Día= new Día();
public static const MIERCOLES:
Día= new Día();
public static const JUEVES:
Día= new Día();
public static const VIERNES:
Día= new Día();
public static const SABADO:
Día= new Día();
public static const DOMINGO:
Día= new Día();



En ActionScript 3.0 no se emplea esta técnica, pero la utilizan muchos desarrolladores que prefieren la verificación de tipos mejorada que proporciona. Por ejemplo, un método que devuelve un valor de enumeración puede restringir el valor devuelto al tipo de datos de la enumeración. El código siguiente muestra, además de una función que devuelve un día de la semana, una llamada a función que utiliza el tipo de la enumeración como una anotación de tipo:

function getDía():Día
{
    var date:Date = new Date();
    var retDía:Día;
    switch (date.day)
    {
        case 0:
            retDía = Día.LUNES;
        break;
        case 1:
            retDía = Día.MARTES;
        break;
        case 2:
            retDía = Día.MIERCOLES;
        break;
        case 3:
            retDía = Día.JUEVES;
        break;
        case 4:
            retDía = Día.VIERNES;
        break;
        case 5:
            retDía = Día.SABADO;
        break;
        case 6:
            retDía = Día.DOMINGO;
        break;
    }
    return retDía;
}
var DíaSemana:Día = getDía();



También se puede mejorar la clase Día de forma que asocie un entero con cada día de la semana y proporcione un método toString() que devuelva una representación de cadena del día. Se puede mejorar la clase Día de esta manera como ejercicio.


Clases de activos incorporados:
ActionScript 3.0 utiliza clases especiales, denominadas clases de activos incorporados, para representar elementos incorporados. Un activo incorporado es un activo, como un sonido, una imagen o una fuente, que se incluye en un archivo SWF en tiempo de compilación. Incorporar un activo en lugar de cargarlo dinámicamente garantiza que estará disponible en tiempo de ejecución, pero a cambio el tamaño del archivo SWF será mayor.

Utilización de clases de activos incorporados en Flash:
Para incorporar un activo, hay que añadir primero el activo a una biblioteca de archivo FLA. A continuación, hay que usar la propiedad linkage del activo para asignar un nombre a la clase de activo incorporado del activo. Si no se encuentra una clase con ese nombre en la ruta de clases, se generará una clase automáticamente. Después se puede utilizar una instancia de la clase de activo incorporado y utilizar las propiedades y los métodos definidos por la clase.
Por ejemplo, se puede utilizar el código siguiente para reproducir un sonido incorporado vinculado a una clase de activo incorporado denominada PianoMusic:

var piano:PianoMusic = new PianoMusic();
var sndChannel:SoundChannel = piano.play();
































































































































Brindanos tus Donaciones