Tableur
CS-108 — Série 8
Introduction
Le but de cette série est de vous familiariser avec le patron Observer en l'appliquant pour concevoir un tableur très simple. Notez que même si ce tableur est similaire à celui présenté dans les notes de cours, il est néanmoins suffisamment différent pour que cette série ne soit pas un simple exercice de copie de code.
Pour commencer, créez un nouveau projet pour cette série et importez-y le contenu de l'archive Zip que nous mettons à votre disposition.
Cette archive contient les classes suivantes :
Cell
, qui représente une cellule du tableur, actuellement non observable, et qu'il vous faudra modifier,Spreadsheet
, qui contient le programme principal et qu'il ne vous faudra presque pas modifier.
Attention, la classe Spreadsheet
utilise JavaFX, il vous faut donc l'installer sur votre ordinateur si ce n'est pas déjà fait, puis ajouter la bibliothèque au projet en suivant les instructions de notre guide sur le sujet.
La classe Spreadsheet
est une application graphique qui construit un tableur très simple de 9×9 cellules. Les colonnes du tableur sont étiquetées avec les lettres de A à I, tandis que les lignes le sont avec les chiffres de 1 à 9. Une cellule est nommée en fonction de sa colonne et de sa ligne. Par exemple, la cellule en haut à gauche porte le nom A1
.
Le contenu d'une cellule peut être modifié en cliquant sur elle, ce qui provoque l'apparition de son nom en bas à gauche de la fenêtre, et de son contenu actuel dans le champ textuel adjacent. En modifiant ce champ et en pressant sur la touche entrée (return), on modifie le contenu de la cellule.
Une cellule peut contenir soit :
- une valeur constante, qui doit être un entier positif, p.ex
12
, soit - une formule, qui peut être une addition (
+
), soustraction (-
), multiplication (*
) ou division (/
) de deux cellules, p.ex.=A1+A2
pour la somme du contenu des cellulesA1
etA2
.
Attention, le format des formules est très restrictif et aucune espace n'est tolérée entre les noms de cellules et l'opérateur. N'oubliez pas le signe =
en tête.
Dans sa version actuelle, le tableur permet bien de modifier le contenu des cellules mais les valeurs des cellules ne sont pas correctement affichées, car ces dernières ne sont pas observables. Le but de cette série est de corriger cela pour obtenir une version fonctionnelle du tableur.
Avant de poursuivre, ouvrez la classe Cell
et lisez son code pour le comprendre. Vous verrez en particulier que, dans un soucis de simplicité, le contenu d'une cellule est représenté de manière uniforme par :
- une chaîne
contentString
contenant la représentation textuelle du contenu de la cellule, p.ex. la chaîne12
pour une cellule contenant 12, ou la chaîne=A1+A2
pour une cellule contenant la somme des cellulesA1
etA2
, - une liste de cellules
arguments
qui est soit vide pour les cellules de valeur constante, soit composée d'exactement deux cellules pour les cellules contenant une formule, - un opérateur binaire
operator
de typeIntBinaryOperator
qui contient l'opérateur binaire permettant de calculer la valeur de la formule associée à la cellule.
Pour les cellules contenant une valeur constante, l'opérateur ignore ses deux arguments et retourne toujours la valeur de la cellule. Le constructeur de la classe Cell contient un exemple de tel opérateur constant.
Grâce à cet « opérateur constant », il est possible de n'avoir qu'une seule classe pour les cellules, plutôt que deux comme dans les notes de cours, ce qui simplifie les choses lorsque le contenu d'une cellule change de type (de constant vers formule, ou vice versa).
Exercice 1
Le but du premier exercice est de rendre les cellules du tableur observables, afin qu'elles se mettent à jour correctement.
Pour cela, commencez par définir deux interfaces :
- la première, nommée
Subject
, a pour but d'être implémentée par les classes pouvant être sujet d'observation, et contient deux méthodes : l'une pour ajouter un observateur au sujet, l'autre pour le supprimer, - la seconde, nommée
Observer
, a pour but d'être implémentée par les classes désirant en observer d'autres, et contient une seule méthode qui est appelée lorsqu'un sujet observé par l'observateur a une nouvelle valeur.
Notez que l'interface Observer
est une interface fonctionnelle, et que vous pouvez donc lui attacher l'annotation correspondante si vous le désirez.
Une fois ces interfaces écrites, définissez une classe héritable nommée AbstractSubject
dont le but est de fournir des mises en œuvre par défaut des méthodes d'ajout et de suppression d'observateurs, ainsi qu'une méthode protégée permettant d'avertir tous les observateurs que le sujet a changé. Cette dernière méthode a pour but d'être appelée par les sous-classes de AbstractSubject
lorsque leur contenu a changé.
A ce stade, tout est en place pour rendre les cellules observables. Pour ce faire :
- faites hériter la classe
Cell
deAbstractSubject
, afin qu'elle puisse être sujet d'observation (par d'autres cellules, entre autres), - faites en sorte que les instances de la classe
Cell
informent leurs observateurs lorsque leur valeur (retournée pargetValue
) change, - faites implémenter l'interface
Observer
àCell
, afin que ses instances puissent être informées des changements de contenu des autres cellules dont elles dépendent éventuellement, - faites en sorte que les instances de la classe
Cell
s'enregistrent bien comme observatrices auprès des cellules dont elles dépendent, et mettent au besoin leur valeur à jour lorsque celles-ci changent de valeur.
Cela fait, ouvrez la classe Spreadsheet
et trouvez la ligne indiquée par un commentaire TODO
. A cet endroit, ajoutez un observeur à la cellule cell
pour que, lorsque sa valeur change, le texte du bouton cellButton
soit changé en fonction. Ce changement peut se faire au moyen de la méthode setText
que la classe Button
hérite de Labeled
. Souvenez-vous que Observer
est une interface fonctionnelle, et que vous pouvez donc utiliser une lambda.
A ce stade, votre tableur devrait être fonctionnel, ce que vous pouvez vérifier en entrant des valeurs et des formules dans plusieurs cellules, et en vous assurant que les mises à jour sont correctement propagées.
Exercice 2
Entrez successivement les formules et valeurs suivantes dans votre tableur :
A1=B1+C1
,B1=A1+C1
,C1=1
.
Que se passe-t-il ? Pourquoi ? Pouvez-vous imaginer une solution à ce problème ?
Exercice 3
Entrez successivement les formules et valeurs suivantes dans votre tableur (notez qu'il est normal que C2
soit modifiée à deux reprises) :
A1=10
,B1=1
,C2=5
,C3=B1/C2
,C2=A1-C1
,C1=A1-B1
.
Cela fait, essayez de donner les valeurs successives suivantes à A1
:
A1=20
,A1=30
,A1=5
,A1=4
.
Que se passe-t-il ? Pourquoi ?
En essayant de comprendre le problème, récrivez (à la main) la formule pour la cellule C3
en essayant de la simplifier au maximum. Que constatez-vous ?