Evénements
Plan Evénements Principes Exemples Adapteur
Evénements Les événements permettent de propager et de notifier les changements d’états entre un objet source et un ou plusieurs objets listener.
Implémentation Notifications d’événements propagées des sources vers les listeners par invocation de méthodes Java java.util.EventListener Groupe d’événements de la même catégorie A chaque type d’événement correspond une méthode distincte pour la notification. Classe de listeners d’événements implémente un ensemble donné d’interfaces EventListener. java.util.EventObject l’état associé avec la notification d’un événement
Implémentation Sources d’événements méthodes d’enregistrement doivent se conformer à un design pattern spécifique de nommage classes d’adapteurs sur mesure peuvent s’interposer entre la source et un ou plusieurs listeners pour les relier ou ajouter au comportement de base des listeners.
Notification d’événements
Objets : état de l’événement Par convention, le nom de la classe se termine par “Event”. Sous-classes de java.util.EventObject distinctions logiques entre les types d’événements
Interfaces Event Listeners Pour définir et regrouper les méthodes de gestion des événements. Les interfaces EventListener héritent de java.util.EventListener Par convention, le nom de ces interfaces se termine en “Listener”.
MouseListener, MouseEvent, MouseAdapter
Design pattern pour la signature des méthodes associées aux événements un design pattern standard pour la documentation du système d’événements pour déterminer par programmation les interfaces des listeners réalisées par des tiers construction automatique d’adapteurs génériques. La signature de ce design pattern est: void <eventOccurenceMethodName>(<EventStateObjectType> evt); où <EventStateObjectType> est une sous-classe de java.util.EventObject.
Enregistrement d’un Event Listener Les classes qui déclenchent des événements doivent fournir des méthodes d’enregistrement et de “dés-enregistrement” des listeners. Design pattern : synchronized public void add< ListenerType>(< ListenerType> listener); remove< ListenerType>(< ListenerType> listener);
synchronized Les segments de code qui accèdent le même objet à partir de threads distincts parallèles sont appelés sections critiques. En Java, une section critique peut être un bloc ou une méthode identifiée par le mot-clé synchronized. Un ‘lock’ est associé avec tout objet qui contient du code synchronisé
Synchronized : verrouillage Lorsque le contrôle entre dans une méthode synchronisée, le thread qui a appelé cette méthode verrouille l’objet dont la méthode a été appelé. Les autres threads ne peuvent pas appeler une méthode synchronisée du même objet jusqu’à ce que l’objet soit déverrouillé. L’acquisition et la libération d’un verrou est faite automatiquement et atomiquement par l’exécutable Java.
Enregistrement d’un Event Listener Aspects dépendants de l’implémentation la relation entre ordre d’enregistrement ordre de livraison des événements les effets de l’ajout du même objet eventListener plus d’une fois sur la même source d’événements, le retrait d’un objet eventListener plus d’une fois, le retrait d’un objet eventListener qui n’est pas enregistré
Enregistrement Unicast Event Listener Pour des motivations sémantiques ou d’implémentation, il se peut qu’il ne soit pas approprié ou impraticable que certains événements soient multicast La signature pour un enregistrement d’un EventListener unicast : public void add <ListenerType> ( <ListenerType> listener) throws java.util.TooManyListenersException; public void remove< ListenerType> (< ListenerType> listener); Transmettre null en tant que valeur de listener est illégal, et peut provoquer les exceptions suivantes IllegalArgument-Exception ou NullPointerException.
Sémantique de la livraison des événements Unicast/Multicast par défaut, tous les listeners enregistrés doivent être considérés comme éligibles pour recevoir la notification de l’événement la source peut restreindre l’ensemble des listeners éligibles à un sous-ensemble de ceux qui sont actuellement enregistrés en fonction de critères de sélection dépendants de l’implémentation
Sémantique de la livraison des événements Livraison synchrone La livraison des événements est synchrone par rapport à la source des événements. Exceptions les méthodes des listeners peuvent déclencher des exceptions déclarées les sources d’événements doivent être conscientes que les listeners peuvent déclenchés “par inadvertance” des exceptions non déclarées. si un des listeners de l’exception déclenche une exception, alors c’est une décision de l’implémentation au niveau de la source des événements de décider si elle poursuit ou non la livraison de l’événement aux autres listeners
Sémantique de la livraison des événements Gestion du parallélisme Dans les systèmes multi-thread, la gestion des événements est une cause fréquente de “race condition” ou de deadlock. A race condition is anomalous behavior caused by the unexpected dependence on the relative timing of events les sources d’événements devraient utiliser des méthodes synchronisées et des blocs synchronisés pour accéder aux structures de données qui décrivent les event listeners
Sémantique de la livraison des événements Gestion du parallélisme (suite) il est fortement recommandé que les sources d’événements évitent de conserver les “locks” internes lorsqu’elles appellent des méthodes des listeners elles devraient éviter l’utilisation de méthodes synchronisées pour déclencher un événement et devraient plutôt utiliser un bloc synchronisé pour trouver (e.g. copier la liste des listeners) et par la suite appeler les méthodes des listeners à partir du code non-synchronisé.
Notification des événements public abstract class Model { private Vector<ModelEventListener> listeners_ = new Vector<ModelEventListener>(); synchronized public void addModelEventListener(ModelEventListener aListener){ listeners_.add(aListener); } synchronized public void removeModelEventListener(ModelEventListener aListener){ listeners_.remove(aListener); protected void notify(ModelEvent evt){ Vector<ModelEventListener> listenersClone; synchronized(this){ listenersClone = (Vector<ModelEventListener>) listeners_.clone(); for(ModelEventListener l : listenersClone) { l.modelChanged(evt);
Sémantique de la livraison des événements Modification de l’ensemble des listeners pendant la livraison d’un événement. Les effets exacts de telles mises à jour parallèles sont dépendantes de l’implémentation. Cela signifie qu’un listener peut être de-enregistré et continuer à recevoir subséquemment des événements de la source parce que la livraison d’événements multicast était en cours.
Adapteurs d’événements
Utilisation des adapteurs d’événements Implémentation d’une file entre les sources et les listeners. Filtrage. Démultiplexage de sources multiples d’événements sur un seul listener. Agir comme “wiring manager” générique entre les sources et les listeners.
Exemple de listener - pas joli, joli
Même exemple utilisant un adapteur I public abstract class MouseAdapter implements MouseListener { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e){} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }
Même exemple utilisant un adapteur II
Même exemple utilisant un adapteur III et une classe interne MyClass doit hériter de la classe Applet… public class MyClass extends Applet { private String msg="Applet closing..."; public void listenTo(Component source){ //source : icone, bouton, menu, etc. source.addMouseListener(new MyAdapter()); } class MyAdapter extends MouseAdapter{ public void mouseClicked(MouseEvent evt){ System.out.println(msg); MyClass.this.stop();
Même exemple utilisant une classe interne anonyme
Adapteurs Démultiplexer plusieurs sources d ’événements sur un seul objet
Sécurité Parce que le mécanisme actuel de livraison des événements est synchrone à l’intérieur du thread déclencheur, l’algorithme de vérification de la pile implique les actions du listener sont automatiquement limitées si la source est une applet untrusted.