Interfaces

Une interface est une collection de déclarations de méthodes qui autorise les communications entre des objets différents. Par exemple, ActionScript 3.0 définit l’interface IEventDispatcher qui contient les déclarations des méthodes qu’une classe peut utiliser pour gérer les objets événements. L’interface IEventDispatcher établit une technique standard permettant aux objets de s’échanger les événements. Le code suivant représente la définition de l’interface 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; 
}

Les interfaces sont basées sur la distinction entre l’interface d’une méthode et l’implémentation de celle-ci. L’interface d’une méthode comprend toutes les informations nécessaires pour appeler cette méthode : le nom de la méthode, l’ensemble des paramètres qu’elle reçoit et le type de données qu’elle renvoie. L’implémentation d’une méthode comprend non seulement les informations de l’interface, mais aussi les instructions exécutables qui caractérisent le comportement de la méthode. La définition d’une interface ne contient que les interfaces de la méthode et toute classe qui implémente l’interface doit donc définir les implémentations de la méthode.

Dans ActionScript 3.0, la classe EventDispatcher implémente l’interface IEventDispatcher en définissant toutes les méthodes de cette interface et en ajoutant le corps de chacune de ces méthodes. Le code suivant est extrait de la définition de la classe EventDispatcher :

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

L’interface IEventDispatcher fait office de protocole utilisé par les occurrences d’EventDispatcher pour traiter les objets événements et les transmettre aux autres objets qui ont également implémenté cette interface.

Il est aussi possible de décrire une interface en disant qu’elle définit un type de données, au même titre qu’une classe. En conséquence, une interface peut être utilisée comme annotation de type, tout comme une classe. En tant que type de données, une interface peut également être utilisée avec des opérateurs, par exemple les opérateurs is et as, qui nécessitent un type de données. Toutefois, à l’inverse d’une classe, il n’est pas possible d’instancier une interface. C’est en raison de cette distinction que de nombreux programmeurs voient les interfaces comme des types de données abstraites et les classes comme des types de données concrètes.

Définition d’une interface

La structure de la définition d’une interface est similaire à celle de la définition d’une classe, à ceci près qu’une interface ne peut pas contenir les corps des méthodes. Les interfaces ne peuvent pas comporter des variables ou des constantes, mais elles peuvent contenir des méthodes de lecture et de définition. Pour définir une interface, on utilise le mot-clé interface. Par exemple, l’interface suivante, IExternalizable, fait partie du package flash.utils d’ActionScript 3.0. L’interface IExternalizable définit un protocole pour sérialiser un objet, ce qui correspond à la conversion d’un objet en un format qui convienne au stockage sur un périphérique ou au transport sur un réseau.

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

L’interface IExternalizable est déclarée avec le modificateur de contrôle d’accès public. Les définitions d’interfaces peuvent uniquement être modifiées à l’aide des spécificateurs de contrôle d’accès public et internal. Dans une définition d’interface, les déclarations de méthodes ne peuvent pas comporter de spécificateur de contrôle d’accès.

ActionScript 3.0 respecte la convention de nom selon laquelle les noms des interfaces débutent par un I majuscule, mais vous pouvez utiliser tout identificateur autorisé comme nom d’interface. Les définitions d’interfaces sont souvent placées au niveau supérieur d’un package. Les définitions d’interfaces ne peuvent pas être placées dans une définition de classe ou dans une autre définition d’interface.

Une interface peut étendre une ou plusieurs autres interfaces. Par exemple, l’interface IExample étend l’interface IExternalizable :

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

Toute classe qui implémente l’interface IExample doit comporter non seulement les implémentations de la méthode extra(), mais aussi celles des méthodes writeExternal() et readExternal() héritées de l’interface IExternalizable.

Implémentation d’une interface dans une classe

La classe est le seul élément du langage ActionScript 3.0 qui puisse implémenter une interface. Pour implémenter une ou plusieurs interfaces, on utilise le mot-clé implements dans une déclaration de classe. L’exemple suivant définit deux interfaces, IAlpha et IBeta, ainsi qu’une classe, Alpha, qui les implémente toutes deux :

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 {} 
}

Dans une classe qui implémente une interface, les méthodes implémentées doivent :

  • Utiliser l’identificateur de contrôle d’accès public.

  • Utiliser le même nom que la méthode de l’interface.

  • Avoir le même nombre de paramètres, chacun d’eux étant du type de données correspondant à celui du paramètre équivalent dans la méthode de l’interface.

  • Utiliser le même type de retour.

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

Vous disposez toutefois d’une certaines souplesse pour le nom des paramètres des méthodes que vous implémentez. Bien que le nombre et le type de données des paramètres de la méthode implémentée doivent correspondre à ceux de la méthode de l’interface, il n’est pas obligatoire que les noms des paramètres soient identiques. Par exemple, dans l’exemple ci-dessus, le paramètre de la méthode Alpha.foo() est appelé param.

Par contre, le paramètre correspondant est appelé str dans la méthode de l’interface IAlpha.foo() :

function foo(str:String):String;

Les valeurs par défaut des paramètres offrent également une certaine souplesse. La définition d’une interface peut comporter des déclarations de fonctions avec des valeurs par défaut pour les paramètres. Une méthode qui implémente l’une de ces déclarations de fonction doit disposer d’une valeur par défaut pour le ou les paramètres. Cette valeur doit être du même type de données que celle qui est spécifiée dans la définition de l’interface, mais ce n’est pas forcément le cas pour la valeur réelle. Par exemple, le code ci-dessous définit une interface contenant une méthode dont le paramètre a la valeur 3 par défaut :

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

La définition de classe suivante implémente l’interface Igamma, mais utilise une autre valeur par défaut pour le paramètre :

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

Cette souplesse est due au fait que les règles d’implémentation d’une interface sont spécifiquement conçues afin d’assurer une compatibilité des types de données ; il n’est pas nécessaire, pour ce faire, d’exiger des noms et des valeurs par défaut identiques pour les paramètres.