IPO / A3P – TP2 2425v1
Sujet
Durée : 3-4h (= TP 2.1 + 2.2)
Nota : le travail demandé doit être terminé, en séance ou, à défaut, hors séance.
Cet exercice va consister à modifier des classes d'un exemple de projet BlueJ : le projet maison
Sauvegarder (dans le répertoire TP2) puis ouvrir le fichier proj_maison.jar .
1. Dans
la fenêtre principale de Bluej,
les flèches entre classes définissent des liens de dépendance. Les flèches en
tireté spécifient un lien "uses".
Comme l'indiquent ces flèches, la classe Maison utilise les classes Cercle,
Carre et Triangle, et ces dernières utilisent la classe Canvas.
Veuillez noter que la classe Maison peut utiliser les classes
Cercle, Carre, et Triangle car ces 4 fichiers
.java se trouvent tout simplement dans le même répertoire/dossier.
La classe Canvas définit des utilitaires de bas niveau pour l'affichage graphique d'objets : nous ne
l'étudierons pas.
2. Après
avoir compilé (si nécessaire), créer un objet Carre [ clic droit sur cette
classe puis choisir new Carre() ], le rendre visible, et le déplacer de 200 pixels vers le bas
==> invoquer la méthode depVertical [ clic
droit sur l'objet puis void depVertical() ] ;
créer de même un objet Maison et invoquer
la méthode dessine() sur cette instance.
L'image affichée illustre que l'objet de type Maison est une composition d'objets de
type Cercle, Carre et Triangle. Invoquer
maintenant la méthode place.
Une maison ensoleillée apparait-elle ?
Par contre, les déplacements se font
instantanément car les procédures de déplacements lents ne sont pas encore
écrites correctement ; ce sera l’objet de la deuxième partie de ce
tp.
1. Prendre connaissance du code source de la classe Cercle [ double-clic ].
2. Exercice 3.1.3a : Créer dans la classe Cercle fonction suivante :
o nom : getPosition
o paramètre : aucun
o valeur de retour : un entier représentant la position de l'objet codée par le calcul 1000*x + y, où x et y sont les coordonnées du cercle (on supposera avoir toujours : 0 <= coordonnées < 1000).
3. Compiler, créer un objet de type Cercle, puis tester le bon fonctionnement de la méthode getPosition (la méthode doit apparaître grâce à un clic-droit sur l’objet). Comment savez-vous que c’est le bon résultat ? Inspectez le cercle.
4. Exercice 3.1.3b : Créer dans la classe Cercle un deuxième constructeur :
Rappel : On notera que la classe Cercle possède ainsi deux méthodes de même nom : Cercle. Ceci ne crée pas d'ambiguïté car ces deux méthodes ont des signatures différentes. Cette possibilité qu'offre Java est appelée surcharge. Si vous avez du mal, lisez les indices tout en bas.
5. Compiler, puis créer un objet de type Cercle à l’aide de ce nouveau constructeur. Pourquoi le cercle n’est-il pas visible ? Voir l’exercice suivant pour résoudre ce problème.
6.
Exercice 3.1.3c : Modifier les deux constructeurs (*) pour que le cercle
soit automatiquement visible dès sa création. Regarder la méthode
rendVisible()
pour comprendre pourquoi le cercle n’était pas visible, puis appeler
cette méthode plutôt que positionner aEstVisible à true.
(*) Ce n'est pas normal d'être obligé de faire cette modification deux fois,
c'est à cause de la duplication de code et ce problème sera résolu
à l'exercice 3.1.3d.
7.
Compiler, créer un objet Cercle des 2 façons possibles pour tester le bon
fonctionnement de cette nouvelle version.
Si vous avez du mal, lisez les indices tout en bas.
En travail personnel hors du tp, reportez cette amélioration dans les classes Carre et Triangle.
8.
Exercice 3.1.3d : Vous remarquerez
que les deux constructeurs comportent chacun 5 instructions quasi-identiques,
même si ce ne sont pas avec les mêmes valeurs.
Puisque le deuxième constructeur peut mettre n'importe quelle valeur dans les 4 premiers attributs,
il peut en particulier mettre celles qu'y met le premier constructeur.
Donc pour éviter de la duplication de code, il vaudrait mieux
remplacer toutes les instructions du premier constructeur
par un simple appel du deuxième constructeur, en lui passant des valeurs
des 4 types qu'il attend.
Pour savoir quelles valeurs passer, il suffit de comprendre que le premier constructeur
doit continuer de créer exactement le même cercle qu'avant !
La syntaxe pour qu'un constructeur appelle un autre constructeur (de la même classe) est très précise :
this(
paramètres_attendus_par_le_constructeur_appelé );
De plus, cet appel doit forcément être la première instruction du constructeur.
Faire cette modification pour éviter l'ennemi numéro un en bonne programmation :
la duplication de code !
1. Prendre connaissance du code source de la classe Maison.
2. Exercice 3.1.4a : Modifier la classe Maison de façon à ce que la méthode qui rend la maison visible soit appelée automatiquement à la création de l’objet. Compiler et tester. Tout est bien placé ? Sinon, ajouter ce qu'il faut. Si vous avez du mal, lisez les indices tout en bas.
3.
Exercice 3.1.4b : Modifier
la classe Maison
de façon à ajouter comme 5ème composant du dessin un deuxième soleil.
Faites-en sorte que seule la couleur (pas noire !) soit différente par rapport au premier soleil.
Compiler et tester.
Ce nouveau soleil est-il bien visible ? Sinon, corriger.
metNoirEtBlanc() et metCouleur() fonctionnent-elles
toujours ? Sinon, corriger et
tester.
4.
Exercice 3.1.4c : Créer dans
la classe Maison la méthode suivante
sans modifier la classe Cercle , puis compiler et tester.
5. Exercice 3.1.4d : Modifier la classe Maison de façon à ne pas avoir à répéter 2 fois à peu près la même chose dans getPositionsDeuxSoleils(). Pour cela, créer une nouvelle fonction getPositionSoleil() (publique ou privée ?), retournant une String et acceptant un Cercle en paramètre, et ne retournant la position que de ce cercle. Ensuite, getPositionsDeuxSoleils() n’a qu’à appeler getPositionSoleil() 2 fois. Compiler et tester. Si vous avez du mal, lisez les indices tout en bas.
6. Exercice
3.1.4e : Modifier la méthode getPositionSoleil() pour qu’elle
accepte en plus un paramètre String contenant le nom (que vous avez choisi) du
cercle dont elle retourne la position ;
1. Exercice 3.1.5a : Ajouter des commentaires de documentation aux méthodes que vous avez développées (dans les classes Cercle, Carre, Triangle et Maison) pour qu'elles soient renseignées au moins au même niveau que les autres. Regarder pour chaque classe sa « Documentation » (Interface), puis prendre connaissance de l'arborescence des fichiers générés dans le sous-dossier doc de votre projet et, ouvrir le fichier package-summary.html dans un navigateur.
2. Exercice 3.1.5b : Prendre connaissance de l'arborescence des fichiers générée dans le répertoire proj_maison et, sous navigateur, consulter le fichier package-summary.html. Voyez-vous toutes les classes ?
4.
Pour remédier à ce problème, [fenêtre principale de BlueJ, menu Outils,
choix Générer
la documentation du projet]. Attendre quelques secondes le message de fin
tout en bas de la fenêtre BlueJ,
puis recharger la page et vérifier le résultat en navigant parmi toutes les classes du projet.
1. Dans
la méthode depLentVertical de la classe Carre,
supprimer l'appel à depVertical()
qui déplace d'un seul coup de plusieurs pixels, et provoquer un déplacement
lent en utilisant un appel récursif de cette méthode avec un appel de depVertical
d’un seul pixel à chaque fois
(se déplacer lentement de N pixels revient à se déplacer
"rapidement" d'un pixel puis à se déplacer lentement de N-1 pixels ;
mais au fait, quand le carré va-t-il arrêter de se déplacer ?).
Pour en savoir plus sur la récursivité, lisez
ce mini-cours.
a) Essayez d’abord avec
pDistance toujours positive, sans toucher aux lignes en commentaire. Compiler, tester.
Si vous avez du mal, lisez les indices tout en bas.
b) Essayez ensuite de tenir
compte de la bonne direction (utiliser vDelta en décommentant les premières
lignes des méthodes de déplacements lents). Compiler, tester.
Si vous obtenez une
StackOverflowError ou si la forme clignote indefiniment,
c’est que la récursion ne s’arrête jamais.
[cliquez en bas à droite pour arrêter l’exécution]
2. Reportez vos instructions dans depLentHorizontal en adaptant les noms. Compiler. Tester.
3. Reportez
ces modifications dans les classes Cercle et Triangle. Compiler. Tester. Maison toujours
ensoleillée ?
AIDE : Il est
possible d’afficher les valeurs de vos variables avec
System.out.println(variable);
1. Visualisez le « styleguide » de l'outil javadoc :
https://www.oracle.com/technetwork/java/javase/documentation/index-137868.html#tag .
2. Lisez les parties consacrées aux « tags » @author, @version, @param, @return, et @see . Lisez le reste en travail personnel.
3. Exercice 3.2.2a : Ajoutez/complétez (si nécessaire) les commentaires javadoc en incorporant des @author et un @version dans chaque classe, ainsi que le @return et les @param dans chaque méthode. Regénérez la documentation et vérifiez les informations qui y figurent désormais.
Regénérez la javadoc puis sauvegardez le projet Maison [menu Project, choix Save] et partagez les fichiers avec votre voisin. Un peu fastidieux, non ? Alors essayez plutôt [menu Project, choix Create Jar File.../Exporter...] puis partagez uniquement le fichier .jar ainsi créé. Le destinataire n’aura plus qu’à utiliser [menu Project, choix Open ZIP/JAR...] et à désigner le fichier .jar.
Fermer le projet maison [menu Project, choix Close] , voire BlueJ.
Lire une première fois le guide de style (en anglais) qu’il vous faudra appliquer dans toute l’unité, et pourquoi pas dans la suite de vos études ; sauter certaines notions qui n’ont pas encore été vues.
signature { cas particulier (condition d'arrêt) cas général }
(*) Pour en savoir plus sur la représentation en machine des nombres entiers,
vous pouvez lire
ça.
· Avez-vous bien fait TOUS les exercices, dans TOUTES leurs étapes ?
· Avez-vous compris TOUT ce que vous avez vu ? Sinon, demandez à un intervenant.
· Avez-vous
expérimenté le CodePad ? (Essayez
: int i=12;↵ i*2↵ etc…)
· Si vous avez fini avant l’heure prévue, demandez aux intervenants si vous pouvez partir avant la fin du TP ou bien s’ils considèrent que vous avez encore du travail à faire.
· Sinon,
terminez tout en travail personnel avant le prochain tp.
1) Pour faire l'exercice 3.1.3b :
· Dupliquez le constructeur existant. Ajoutez-lui les paramètres indiqués dans l'énoncé. Servez-vous des paramètres dans les instructions. Ça compile ?
· Pour le 6., remplacez les 5 instructions du premier constructeur par this(); et passez-lui dans les parenthèses les bonnes valeurs pour qu'il crée toujours ce cercle bleu de diamètre 30 et de coordonnées (20,60).
2) Pour faire l'exercice 3.1.3c :
· Ne modifiez que le deuxième constructeur (puisque le premier l'appelle).
· N'utilisez pas 2 instructions lorsqu'une seule suffit !
3) Pour faire l'exercice 3.1.4a :
· Cherchez tous les endroits du code où apparaît aSoleil, dupliquez chaque instruction, et adaptez-la pour aSoleil2.
4) Pour écrire la méthode getPositionsDeuxSoleils :
· N’a-t-elle bien aucun paramètre (elle n’a besoin d’aucune information supplémentaire) ?
· Quelle fonction (de la classe Cercle) retourne la position du cercle ?
· Comment extraire d’un nombre de la forme 20060 les coordonnées 20 et 60 (voir aide dans le sujet) ?
· Construire la chaîne de caractères bout après bout en utilisant un + avant chaque bout (de type String ou int) supplémentaire.
5) Pour écrire la méthode getPositionSoleil :
· Relisez l’énoncé pour savoir quel type de valeur cette fonction retourne, et quel est le type de son paramètre.
· Reprenez la moitié de ce que vous avez écrit 2 fois dans la méthode getPositionsDeuxSoleils, mais en appliquant les appels de méthode au cercle passé en paramètre (dans getPositionSoleil) plutôt qu’à un cercle précis (comme this.aSoleil2 par exemple).
· Il ne reste plus qu’à remplacer la majeure partie de getPositionsDeuxSoleils par 2 appels à getPositionSoleil, des deux côtés de la chaîne " | " qui sépare les 2 soleils.
6) Pour écrire les méthodes de déplacement lent (par exemple vertical) par récursivité :
· Respectez pas à pas les étapes proposées dans l’énoncé ; quand on parle d’un déplacement « normal » ou « rapide », on désigne juste un appel à depVertical.
· N’oubliez ni le test d’arrêt (quand il n’y a aucun pixel à parcourir, que faut-il faire ?), ni de modifier le paramètre (pour que la distance restant à parcourir diminue à chaque fois).
· Lorsque cela fonctionne vers le bas, intéressez-vous à la variable vDelta (en commentaire) ; au lieu d’enlever 1 au paramètre à chaque fois, ne vaudrait-il pas mieux enlever vDelta (dont la valeur change selon le sens de déplacement souhaité) pour que cela fonctionne aussi vers le haut ?
7) Pour écrire la fonction factorielle :
· n! = n x (n-1)! et par convention 0! = 1 (ne pas s'occuper des entiers négatifs)