Interfaces

Una interfaz es una colección de declaraciones de métodos que permite la comunicación entre objetos que no están relacionados. Por ejemplo, ActionScript 3.0 define la interfaz IEventDispatcher, que contiene declaraciones de métodos que una clase puede utilizar para controlar objetos de evento. La interfaz IEventDispatcher establece una forma estándar de pasar objetos de evento entre objetos. El código siguiente muestra la definición de la interfaz IEventDispatcher:

public interface IEventDispatcher 
{ 
    function addEventListener(type:String, listener:Function,  
            useCapture:Boolean=false, priority:int=0, 
            useWeakReference:Boolean = false):void; 
    function removeEventListener(type:String, listener:Function,  
            useCapture:Boolean=false):void; 
    function dispatchEvent(event:Event):Boolean; 
    function hasEventListener(type:String):Boolean; 
    function willTrigger(type:String):Boolean; 
}

Las interfaces se basan en la distinción entre la interfaz de un método y su implementación. La interfaz de un método incluye toda la información necesaria para llamar a dicho método, como el nombre del método, todos sus parámetros y el tipo que devuelve. La implementación de un método no sólo incluye la información de la interfaz, sino también las sentencias ejecutables que implementan el comportamiento del método. Una definición de interfaz sólo contiene interfaces de métodos; cualquier clase que implemente la interfaz debe encargarse de definir las implementaciones de los métodos.

En ActionScript 3.0, la clase EventDispatcher implementa la interfaz IEventDispatcher definiendo todos los métodos de la interfaz IEventDispatcher y añadiendo el código a cada uno de los métodos. El código siguiente es un fragmento de la definición de la clase EventDispatcher:

public class EventDispatcher implements IEventDispatcher 
{ 
    function dispatchEvent(event:Event):Boolean 
    { 
        /* implementation statements */ 
    } 
 
    ... 
}

La interfaz IEventDispatcher constituye un protocolo que las instancias de EventDispatcher utilizan para procesar objetos de evento y pasárselos a otros objetos que también tienen implementada la interfaz IEventDispatcher.

Otra forma de describir una interfaz es decir que define un tipo de datos de la misma manera que una clase. Por consiguiente, una interfaz se puede utilizar como una anotación de tipo, igual que una clase. Al ser un tipo de datos, una interfaz también se puede utilizar con operadores, como los operadores is y as, que requieren un tipo de datos. Sin embargo, a diferencia de una clase, no se puede crear una instancia de una interfaz. Esta distinción hace que muchos programadores consideren que las interfaces son tipos de datos abstractos y las clases son tipos de datos concretos.

Definición de una interfaz

La estructura de una definición de interfaz es similar a la de una definición de clase, con la diferencia de que una interfaz sólo puede contener métodos sin código de método. Las interfaces no pueden incluir variables ni constantes, pero pueden incluir captadores y definidores. Para definir una interfaz se utiliza la palabra clave interface. Por ejemplo, la siguiente interfaz, IExternalizable, forma parte del paquete flash.utils en ActionScript 3.0. La interfaz IExternalizable define un protocolo para serializar un objeto, lo que implica convertir un objeto en un formato adecuado para el almacenamiento en un dispositivo o para el transporte a través de la red.

public interface IExternalizable 
{ 
    function writeExternal(output:IDataOutput):void; 
    function readExternal(input:IDataInput):void; 
}

La interfaz IExternalizable se declara con el modificador de control de acceso public. Las definiciones de interfaz sólo pueden modificarse mediante los especificadores de control de acceso public e internal. Las declaraciones de métodos en una definición de interfaz no pueden incluir ningún especificador de control de acceso.

ActionScript 3.0 sigue una convención por la que los nombres de interfaz empiezan por una I mayúscula, pero se puede utilizar cualquier identificador válido como nombre de interfaz. Las definiciones de interfaz se suelen colocar en el nivel superior de un paquete. No pueden colocarse en una definición de clase ni en otra definición de interfaz.

Las interfaces pueden ampliar una o más interfaces. Por ejemplo, la siguiente interfaz, IExample, amplía la interfaz IExternalizable:

public interface IExample extends IExternalizable 
{ 
    function extra():void; 
}

Cualquier clase que implemente la interfaz IExample debe incluir implementaciones no sólo para el método extra(), sino también para los métodos writeExternal() y readExternal() heredados de la interfaz IExternalizable.

Implementación de una interfaz en una clase

Una clase es el único elemento del lenguaje ActionScript 3.0 que puede implementar una interfaz. Se puede utilizar la palabra clave implements en una declaración de clase para implementar una o más interfaces. En el ejemplo siguiente se definen dos interfaces, IAlpha e IBeta, y una clase, Alpha, que implementa las dos interfaces:

interface IAlpha 
{ 
    function foo(str:String):String; 
} 
 
interface IBeta 
{ 
    function bar():void; 
} 
 
class Alpha implements IAlpha, IBeta 
{ 
    public function foo(param:String):String {} 
    public function bar():void {} 
}

En una clase que implementa una interfaz, los métodos implementados deben:

  • Utilizar el identificador de control de acceso public.

  • Utilizar el mismo nombre que el método de interfaz.

  • Tener el mismo número de parámetros, cada uno con un tipo de datos que coincida con los tipos de datos de los parámetros del método de interfaz.

  • Devolver el mismo tipo de datos.

    public function foo(param:String):String {}

Sin embargo, hay cierta flexibilidad para asignar nombres a los parámetros de métodos implementados. Aunque el número de parámetros y el tipo de datos de cada parámetro del método implementado deben coincidir con los del método de interfaz, los nombres de los parámetros no tienen que coincidir. Por ejemplo, en el ejemplo anterior el parámetro del método Alpha.foo() se denomina param:

En el método de interfaz IAlpha.foo(), el parámetro se denomina str:

function foo(str:String):String;

También hay cierta flexibilidad con los valores predeterminados de parámetros. Una definición de interfaz puede incluir declaraciones de funciones con valores predeterminados de parámetros. Un método que implementa una declaración de función de este tipo debe tener un valor predeterminado de parámetro que sea miembro del mismo tipo de datos que el valor especificado en la definición de interfaz, pero el valor real no tiene que coincidir. Por ejemplo, el código siguiente define una interfaz que contiene un método con un valor predeterminado de parámetro igual a 3:

interface IGamma 
{ 
    function doSomething(param:int = 3):void; 
}

La siguiente definición de clase implementa la interfaz Igamma, pero utiliza un valor predeterminado de parámetro distinto:

class Gamma implements IGamma 
{ 
    public function doSomething(param:int = 4):void {} 
}

La razón de esta flexibilidad es que las reglas para implementar una interfaz se han diseñado específicamente para garantizar la compatibilidad de los tipos de datos y no es necesario exigir que los nombres de parámetros y los valores predeterminados de los parámetros sean idénticos para alcanzar ese objetivo.