TD5 - Le patron Observer/Observable

De $1

 

Note : le td est repris et modifié à partir d'ancien tp. Les noms des auteurs originaux ont été laissés dans les fichiers sources. Merci à eux.

Introduction

Java propose en standard une implantation du pattern Observer/Observable. Ce pattern permet de gèrer facilement l'affichage et la mise à jour de plusieurs vues d'un même objet, concept que vous avez peut-être déjà manipulé avec Excel (un histogramme et un camembert qui bougent lorsqu'on change les valeurs d'une colonne)... Nous vous proposons d'illustrer ce pattern en écrivant un programme qui fait à peu près la même chose qu'Excel : dessiner des graphiques correspondant à un tableau de valeurs entières, par exemple des histogrammes 2D. Lorsque les valeurs entières du tableau changent, les graphiques aussi.

Aperçu du résultat

Téléchargez l'archive observer.jar et exécutez là (java -jar observer.jar).

Initialement, vous remarquez trois boutons en haut : "random", "nouvelle vue interne" et "nouvelle vue externe". En dessus, il y a un histogramme qui rapidement se met à bouger. En fait, c'est le tableau qu'il représente qui change toutes les secondes. Le bouton "random" permet de changer également les valeurs du tableau. Les nouvelles vues permettent de créer de nouvelles vues du tableau :

  • en interne, cela ajoute un autre histogramme dans la fenêtre (il représente les mêmes données et se redessine en même temps). Ces histogrammes internes sont organisés dans un GridLayout dont le nombre de lignes augmente en fonction du nombre de vues (cliquez "lentement" 5, 6 fois sur le bouton "nouvelle vue interne" et observez la réorganisation).
  • en externe, cela ajoute un histogramme, courbe ou camembert dans une autre fenêtre. L'histogramme représente les mêmes données et est également "synchronisé".

Le but de ce Tp est de vous faire réaliser ce programme pour mettre en évidence l'intérêt du patron Observer/Observable et la difficulté pour le mettre en oeuvre. Ici, nous utiliserons la classe Observable et l'interface Observer proposées par Java, mais nous aurions très bien pu faire nos propres événements et nos propres interfaces comme en cours !

Le déroulement

Télécharger le projet Eclipse (miage.m1.td.observer.zip) et l'importer dans votre environnement de travail. File/Import..., "Existing Projects into workspace", Select Archive file, ...

La classe TableauEntierEtendue est fournie: elle décrit un tableau de nombres entiers Observable, et fournit des méthodes pour le remplir aléatoirement et prévenir les différents Observers, s'il y en a, que les valeurs ont changées. Elle implémente l'interface ITableauEntier également fournie.

On vous fournit aussi la classe GrapheurTabEntiers qui hérite de JComponent et implémente l'interface Observer. Cette classe est le contrôleur selon le patron MVC. ITableauEntier est le modèle et IVueTableau est la vue. La classe GrapheurTabEntiers joue le rôle du contrôleur. Elle reçoit les notifications du modèle et demande à la vue de se redessiner.

  1. Compléter la classe GrapheurTabEntiers pour demander de redessiner le composant lorsqu'on reçoit une notification du modèle. Ce travail consiste simplement à ajouter une instruction dans la méthode update. 
  2. Ecrire une classe VueBar qui implémente l'interface IVueTableau et dessine un histogramme en fonction des valeurs du modèle. L'interface IVueTableaupossède une seule méthode dessine(...) qui fournie en paramètres, un objet de type Graphics dans lequel on va dessiner, un Component qui connaît en particulier la dimension de la zone graphique disponible et un modèle qui contient les valeurs à dessiner. 
  3. Ecrire une classe TestObserverObservable qui contient le programme principal et qui créera une fenêtre. Vous utiliserez une seule instance deTableauEntierEtendu. Il est très important de ne pas dupliquer les données. Vous créerez également une instance de GrapheurTabEntiers qui écoute les notifications du modèle. Dans un premier temps, on utilisera systématiquement la vue VueBar pour dessiner le tableau d'entiers. 
  4. La fenêtre (JFrame) doit contenir dans la zone "Center" (son Layout Manager par défaut est un BorderLayout) l'instance du GrapheurTabEntiers, et dans la zone "North" un bouton "random" qui, lorsqu'on clique dessus, ré-initialise aléatoirement le tableau TableauEntierEtendu (voir la méthode melange()). L'histogramme doit se redessiner automatiquement si vous avez tout fait comme il faut. 
  5. Maintenant, essayer d'avoir plusieurs vues du même TableauEntierEtendu. Ajouter un bouton "nouvelle vue interne" pour ajouter une nouvelle vue dans la fenêtre (une nouvelle instance de GrapheurTabEntiers). Pour cela, vous serez certainement amené à changer la façon d'ajouter les histogrammes. Voici quelques mots-clefs pour vous mettre sur la piste : JPanel, South, GridLayout, pack. Idem, lorsqu'on clique sur le bouton "random", toutes les vues doivent bouger. 
  6. Maintenant, ajouter le bouton "nouvelle vue externe" et le comportement associé, tel que l'aperçu vous l'a illustré. Faire en sorte de bien quitter l'application (en fermant chaque fenêtre les unes après les autres). 
  7. Créer deux nouvelles classes qui implémentent IVueTableau, et qui permettent d'afficher le tableau comme une courbe ou comme un camembert et permettez le choix de la type de vue lorsqu'on crée une vue interne ou externe.
  8. Ecrire une classe AnimeTableau qui utilise un Thread pour mélanger le tableau automatiquement toutes les secondes.