La nouvelle méthode de programmation d'ActionScript 2 semble poser beaucoup de problèmes aux utilisateurs de la programmation évenementielle (dont je fais partie). En fait, mon problème essentiel avec l'AsBroadcaster existant porte sur deux points :

  • On ne peut plus initialiser le prototype, mais uniquement l'instance (dans le constructeur)
  • Si on veut une classe non-dynamique, il faut déclarer les fonctions addListener, removeListener et broadcastMessage.
C'est à ces deux problèmes que je me suis attaqué.

Ma petite solution perso ne règle pas tous ces problèmes, dans le sens ou on ne peut pas faire de l'héritage dynamique, mais j'ai crée une classe nommée EventBroadcaster (je sais, le nom est pas top, mais j'ai pas osé LAlexBroadcaster, ca fait un peu mégalo ... :)).
class EventBroadcaster {
        var _listeners:Array;
        // -- Constructeur
        // Initialise le tableau '_listeners'
        private function EventBroadcaster() {
                this._listeners = new Array();
        }
        // Emet un évenement passé en paramètre
        public function broadcastMessage (msg:String) {
                // Parcoure le tableau '_listeners'
                for (var i=0 ; i<this._listeners.length ; i++) {
                        // Si l'évenemet est présent dans un écouteur, on l'applique
                        // Avec les arguments passés aprés le nom de l'évenement
                        if (typeof this._listeners[i][msg] == "function") {
                                this._listeners[i][msg].apply(this._listeners[i],arguments.slice(1));
                        }
                }
        }
        // Rajoute un écouteur a un objet
        public function addListener(o:Object) {
                // Supprime d'abord l'écouteur
                this.removeListener(o);
                // Ajoute l'objet en tant qu'écouteur
                this._listeners.push(o);
        }
        // Supprime un écouteur
        public function removeListener(o:Object) {
                // Parcoure le tableau '_listeners'
                // Si l'objet est trouvé, on le supprime et on arrete la boucle
                for (var i=0 ; i<this._listeners.length ; i++) {
                        if (this._listeners[i] == o) {
                                this._listeners.splice(i,1);
                                break;
                        }
                }
        }
        // Initialisation d'une instance de classe DYNAMIQUE
        public static function initialize(o:Object) {
                // On crée tout simplement le tableau '_listeners'
                // et les méthodes pour broadcaster
                o._listeners = new Array();
                o.addListener = EventBroadcaster.prototype.addListener;
                o.removeListener = EventBroadcaster.prototype.removeListener;
                o.broadcastMessage = EventBroadcaster.prototype.broadcastMessage;
        }
        // Initialisation d'une classse DYNAMIQUE
        // ou initialisation de la classe d'un instance DYNAMIQUE
        // La classe doit être dinamique, tout simplement pour
        // pouvoir faire appel a this.addListener ou this.broadcastMessage
        public static function initializeClass(o:Object) {
                var curParent:Object;
                if (typeof o == "function") {
                        curParent = o.prototype;
                } else {
                        curParent = o.__proto__;
                }
                do {
                        switch (curParent.__proto__) {
                                // La classe hérite deja de EventBroadcaster
                                case EventBroadcaster.prototype :
                                        return;
                                // On est au niveau le plus bas de la chaine de protos
                                // On glisse le prototype dans la chaine
                                case Object.prototype :
                                        curParent.__proto__ = EventBroadcaster.prototype;
                                        return;
                                // Aucun des cas précédents, on remonte d'un cran dans
                                // la chaîne de prototypes
                                default :
                                        curParent = curParent.__proto__;
                        }
                } while (true);
        }
}
Elle peut être utilisée de deux manières :

  • Par héritage C'est de loin la méthode que je préfère, car elle ne nécessite pas une classe dynamique, ni une déclaration des méthodes de broadcast. Le seul inconvénient est que on n'a pas toujours le choix car l'héritage multiple n'existe pas en AS2. Mais on peut toujours faire hériter la classe mère de EventBroadcaster ... class CustomClass extends EventBroadcaster {
            var _prop:Number = 10;
            function CustomClass(prop:Number) {
                    this.addListener(this);
                    this._prop = prop;
            }
            function sendEvent() {
                    this.broadcastMessage("onEvent","Test d'évenement");
            }
            function onEvent(str) {
                    trace(str + " : " + this._prop);
            }
    }
    Et on l'utilise ainsi :var myClass = new CustomClass(20);
    myClass.sendEvent();
  • Par l'utilisation de initialize ou initializeClass
    • La méthode statique initialize fonctionne comme pour AsBroadcaster. Bien évidemment, il faut que la classe soit dynamique, pour pouvoir lui ajouter les fonction, et pouvoir appeler la méthode broadcastMessage dans les méthodes de la classe.
    • La méthode initializeClass prend en paramètre soit une classe et fait hériter cette classe de EventBroadcaster, soit un objet et fait hériter la classe de cet objet de EventBroadcaster : c'est de l'héritage dynamique à l'aide de la chaine de prototypes.
    dynamic class CustomClass {
            var _prop:Number = 10;
            function CustomClass(prop:Number) {
                    EventBroadcaster.initializeClass(this);
                    this._listeners = [];
                    this.addListener(this);
                    this._prop = prop;
            }
            function sendEvent() {
                    this.broadcastMessage("onEvent","Test d'évenement");
            }
            function onEvent(str) {
                    trace(str + " : " + this._prop);
            }
    }

    Et l'utilisation est la même que celle donnée précédemment. L'avantage est que les méthodes addListener, removeListener et broadcastMessage ne se retrouvent pas dans chaque instance ...

Voila pour mon étude personnelle sur la question ! 8)

::Télécharger EventBroadcaster.as::