AS3: Faites le Signal !

Il y a plusieurs années, roulant en voiture dans Casablanca, je fus arrêté par un gendarme local qui me fit les gros yeux :

– Vous n’avez pas fait le signal !

Je n’ai pas compris tout de suite de quoi il voulait parler, mais effectivement, après un certain temps de discussion, je dus admettre que j’avais oublié de mettre mon … clignotant. 

Signal200

(http://freefoto.org/preview/23-30-65?ffid=23-30-65&k=Semaphore+signal)

 

Dans cet article, je vais expliquer l’intérêt d’une bibliothèque AS3 qui permet de « faire le signal », c-a-d à une classe d’envoyer des événements vers le reste de l’application.

Gérer les Custom Events en Flex

Dans Flex, dès qu’on veut passer des données dans un événement, on se retrouve contraint à une mécanique assez lourde qui implique l’écriture de beaucoup de code sans que l’outil nous assiste pour rendre l’ensemble cohérent. C’est à la fois un concept fondamental et incontournable pour assurer le découplage entre les différents composants et l’un des process de programmation les plus lourds de Flex.

Voyons un exemple pratique.

Exemple

La classe Imdb , membre d’une Librairie, me permet de charger un film depuis un service HTTP qui publie une API d’interrogation d’IMDb (Internet Movie Database). Imdb étend EventDispatcher et utilise HTTPService. Le programme appelant lui passe un titre de film et la classe doit retourner un objet IMDBvo qui décrit le film en question.

En raison de la nature synchrone de l’exécution de code dans Flex, la classe Imdb doit émettre un événement indiquant que la description du film a bien été chargée depuis le site d’IMDb et qu’elle est disponible pour utilisation, en l’occurrence affichage dans un formulaire.

Processus

Voici comment cela s’écrit en Flex. Nous devons procéder en plusieurs étapes :

1)

Lorsque la classe Imdb reçoit le résultat de la requête httpservice, elle crée ce que l’on nomme un custom Event, ici de type ImdbEvent, puis elle émet cet événement:

var e:ImdbEvent=new ImdbEvent(ImdbEvent.RESULT,imdb);

this.dispatchEvent(e);

La création de l’événement requiert deux paramètres : son type (ImdbEvent.RESULT) et l’objet imdb de type IMDBvo (un value object, c-a-d un objet ne contenant que des données) récupéré depuis le site distant.

2) 

La classe ImdbEvent doit donc avoir été créée au préalable. C’est un code qui généralement ne présente guère d’intérêt :

package com.ckti.westernslib.events

{

import com.ckti.westernslib.data.vo.IMDbvo;

import flash.events.Event;

public class ImdbEvent extends Event

{

public static const RESULT:String = « result »;

public var imdb:IMDbvo;

public function ImdbEvent(type:String, imdb:IMDbvo){

super(type);

this.imdb=imdb;

}

override public function clone():Event{

return new ImdbEvent(type, imdb);

}

 

}

}

Notons en particulier la déclaration d’une constante RESULT. Celle-ci a pour rôle de faciliter la saisie en proposant de l’auto-complétion sur le type d’objet décrit par une simple chaîne de caractères : « result ».

3) 

La classe Imdb doit maintenant prévenir le reste du monde qu’elle peut émettre des événements de type ImdbEvent.RESULT

Flex utilise pour cela un système déclaratif de méta-données en en-tête de la classe:

[Event(name=« ImdbEvent.RESULT », type=« com.ckti.westernslib.events.ImdbEvent »)]

4)

le code appelant, celui qui attend desespérément le détail du film dont il a passé le titre, doit déclarer un écouteur d’événements :

appModel.imdb.addEventListener(ImdbEvent.RESULT,imdb_resultHandler);

5)

Puis quand il reçoit l’événement tant attendu, il faut le traiter et supprimer l’écouteur d’événement :

private function imdb_resultHandler(event:ImdbEvent):void{

imdb=event.imdb;

appModel.imdb.removeEventListener(ImdbEvent.RESULT,imdb_resultHandler);

}

Assez lourd !

Je ne sais pas vous, mais moi c’est le genre de séquence de codage que je trouve assez pénible…D’autant plus :

– qu’elle impose une intervention sur au moins trois classes différentes;

– qu’elle va se répéter pour chaque événement qui devra transporter des données spécifiques…c-a-d très souvent !

La bibliothèque as3-signals

Que ce soit par des solutions personnalisées ou au travers de frameworks très codifiés, la communauté Flex/AS3 a proposé différentes manières de résoudre ce problème.

Pour différentes raisons que je ne développerai pas ici, le recours à des frameworks peut se révéler source de complications. D’où mon intérêt pour une bibliothèque qui a suscité beaucoup de buzz dans la communauté Flex depuis sa création en 2009 : as3-signals de Robert Penner.

Robert Penner : « Signals is a new approach for AS3 events, inspired by C# events and signals/slots in Qt.« 

Je ne vais pas ici décrire cette bibliothèque, je vous renvoie aux excellents liens référencés à la fin de ce billet. Je vais me contenter de montrer comment son utilisation permet de simplifier considérablement (dramatically diraient nos amis anglo-saxons) l’exemple précédent.

Exemple revu façon as3-signals

1)

Une fois librairie as3-signals-v0.8.swc liée à mon projet, la classe Imdb va déclarer une nouvelle variable d’instance qui sera une référence à un objet de type Signals :

public var resultSignal:Signal;

Lors de la création d’un nouvel objet Imdb, ce nouveau membre est instancié en lui passant le type des paramètres transmis par le signal, ici la classe IMDBvo :

resultSignal=new Signal(IMDbvo);

Le nombre de paramètres est bien entendu variable.

Enfin, à réception du résultat de la requête httpService, au lieu de renvoyer un événement de type ImdbEvent, c’est maintenant ce nouveau signal qui va être propagé en véhiculant l’objet imdb :

resultSignal.dispatch(imdb);

2)

La phase 2, création d ‘un CustomEvent, n’est plus nécessaire

3) 

La phase 3 non plus, l’événement est maintenant matérialisé sous forme de signal par une variable publique de la classe.

4) 

modifions le code d’appel de notre classe pour se mettre à l’écoute du signal :

appModel.imdb.resultSignal.addOnce(onImdbResult);

La fonction addOnce(écouteur d’événement) évite de devoir appeler removeEventListener, une fois le signal reçu, l’écouteur est automatiquement retiré.

5) 

il nous reste à créer la fonction d’écoute onImdbResult pour récupérer directement l’objet IMDbvo :

private function onImdbResult(imdb:IMDbvo):void{

this.imdb=imdb;

}

Qu’en pensez-vous ?

Je trouve, quant à moi, que le recours à as3-signals simplifie très notablement ce processus lourd et répétitif. Le signal est proposé par auto-complétion lors de l’utilisation de la classe :

Signalautocomplete

Limitations

Je vais me contenter de lister deux inconvénients que je trouve à prendre en compte avant tout choix. Encore une fois, vous trouverez de nombreuses discussions très techniques sur ce sujet dans les liens en fin de billet.

1)

Le contrôle des types de paramètres se fait au Runtime, pas lors de compilation. rien ne vous empêche d’écrire :

var label:Label=new Label();

resultSignal.dispatch(label);

Alors que vous avez initialement déclaré passer un objet de type IMDbvo.

2) 

Lors de la déclaration d’une instance en MXML, Flex exploite les méta-données pour proposer la liste des événements susceptibles d’être dispatchés par la classe ciblée. Le signal apparait comme une simple variable d’instance dont il faut connaître le rôle.

Mxml

On sort donc du développement « standard » avec Flex ce qui peut compliquer le travail en équipe, la maintenance évolutive, etc.

Aller plus loin…

as3-signals sur GitHub

Le Google Groupe autour d’as3-signals

As3 Signals Resource Roundup

An introduction to AS3 Signals

as3signals – An Awesome Solution to Events/Signals in AS3

Replacing Events with AS3Signals

 

Un commentaire

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :