IFT232
Laboratoire #1
Java et la Programmation orientée objet
Ce laboratoire comporte plusieurs exercices qui se basent sur un morceau de
code déjà écrit. On assume que vous allez réaliser ces exercices dans
l’environnement Eclipse. Le code de base du laboratoire se trouve sur le
lecteur réseau public, c’est l’archive [Link].
Chargez le code de base du laboratoire dans Eclipse. Pour ce faire, vous
pouvez suivre les instructions qui se trouvent dans l’énoncé du devoir #1 (ça
ne fait jamais de tort de le lire :) ).
Reconnaissance dans le code
Tout d’abord, exécutez le code. Pour ce faire, choisissez la classe Labo1Main
et appuyez sur le bouton play (ou choisissez l’option run as... dans le menu
contextuel). Exécutez-le sous forme d’application java. Dans la partie la plus
basse de la fenêtre (la partie console), entrez deux valeurs entières, une fois
le programme démarré.
Le programme actuel affiche un point sur un canevas (surface de dessin).
Les classes actuelles sont les suivantes :
Labo1Main : démarre l’application. Crée une fenêtre, y place une surface de
dessin, obtient du clavier ou d’un fichier reçu en paramètre l’information sur
l’objet à dessiner, puis dessine l’objet en question. Le programme est
présentement capable de dessiner un point sur le canevas.
PanneauDessin : un panneau qui contient une surface pour dessiner. Sa
fonction doDrawing dessine l’objet qu’il a reçu lors de sa création
(présentement un Point).
Point : Une coordonnée X et une coordonnée Y. Sait se dessiner sur un
canevas (c’est une ligne d’un pixel de long). Sait se lire à partir d’un flot
d’entiers (clavier ou fichier).
Vous allez modifier très peu les classes Labo1Main et PanneauDessin. Les
exercices concernent la classe Point, ainsi que plusieurs autres classes que
vous allez écrire vous-même.
Exercice 1 : Ajustez vos lunettes
Le point est très difficile à voir sur le canevas. Modifiez sa fonction dessiner()
afin qu’un X (deux lignes sécantes assez longues pour qu’on les voit bien)
environ) soit affiché, le point étant en plein centre du X.
Exercice 2 : Arrêtez de pitonner comme des singes
Modifiez le profil d’exécution de votre programme pour qu’un fichier soit lu
à la place du clavier pour obtenir les coordonnées du point. Pour savoir
comment procéder, référez-vous à l’énoncé du devoir #1. Le fichier que vous
devriez utiliser comme argument à l’exécution se nomme tout simplement
« point ».
Exercice 3 : Géométrie de base
Écrivez une nouvelle classe Ligne, qui servira à dessiner une ligne sur le
canevas. Elle aura vraisemblablement plusieurs choses parentes avec la
classe point. La ligne peut être constituée de deux points, et devrait pouvoir
se dessiner et se lire à partir d’un flot d’entiers également.
Une fois que votre classe ligne est écrite, modifiez les classes Labo1Main et
PanneauDessin pour que votre ligne soit lue et affichée au lieu du simple
point d’avant. Votre objectif est de modifier uniquement le type de la
variable Point pour le type Ligne dans ces classes, là où c’est applicable. Ligne
devrait offrir les mêmes fonctionnalités que Point du point de vue des classes
Labo1Main et PanneauDessin (les méthodes dessiner et lire).
Exercice 4 : The cloud
Écrivez une nouvelle classe NuagePoints qui représente un nuage de points.
Pour y arriver, vous devez utiliser des structures de données déjà codées,
disponibles via les Collections de java.
Vous pouvez trouver une description brève de la plupart des structures de
données à cette adresse :
[Link]
[Link]
Choisissez une structure qui peut faire l’affaire et utilisez-la pour implanter
le nuage de points. Vous devriez faire usage de votre classe Point déjà
définie.
NuagePoints, tout comme le Point et la Ligne, doit offrir les services
dessiner() et lire().
Une fois que ces services sont supportés, vous pouvez faire la même chose
qu’avec la ligne et modifier les classes Labo1Main et PanneauDessin pour
que votre nuage de points soit lu et affiché à la place d’un point ou d’une
ligne.
Pour définir un nuage de points, vous devriez avoir d’abord un entier qui
donne le nombre de points à lire, puis une suite d’entiers qui représentent
les coordonnées des points en question.
Exercice 5 : Affichage en texte
Afin de pouvoir vérifier que les prochaines modifications fonctionnent, vous
devez modifier ce qui s’affiche présentement à la console (déclenché par la
classe Labo1Main), qui ne fait que donner une description de l’objet qui sera
dessiné.
Pour ce faire, vous devez écrire la méthode toString pour vos classes Point,
Ligne et NuagePoints.
Cette méthode retourne un objet de type String et est supporté par toutes
les classes java. La version originale est définie dans Object et vous produit
simplement le nom de la classe de l’objet, suivi de son adresse mémoire.
Pour rendre l’affichage de vos objets lisibles, surchargez toString pour qu’un
point s’affiche sous cette forme :
(200,300)
Pour une ligne, modifiez toString pour obtenir quelque-chose comme ceci :
(200,300) -> (400,500)
Pour le nuage de points, modifiez toString pour obtenir quelque-chose
comme ceci :
(200,300)
(400,500)
(123,232)
(209,203)
Rappelez-vous que l’opération + est supportée sur les String (concatène deux
String). Par exemple,
String s = "Coordonnée X" + x;
est un énoncé valide dans le cadre de la classe Point (où il existe un membre
de la classe qui s’appelle x).
Exercice 6 : Programme béton
Lorsque vous lisez un nuage de points, plusieurs problèmes peuvent
survenir.
Par exemple, on peut vous donner une quantité négative de points à lire
(auquel cas votre nuage ne contiendrait aucun point), ou la suite d’entiers
qui représente les coordonnées peut être incomplète (fichier trop court).
Afin de vous prémunir contre ces problèmes, modifiez la fonction de lecture
de votre nuage de points afin de traiter ces conditions.
Pour le cas où il vous manquerait des coordonnées, vous devez utilisez le
mécanisme d’exceptions pour réaliser la gestion de cette erreur. La fonction
nextInt de la classe scanner, qui est utilisée pour lire le flot d’entiers, lance
une exception de type NoSuchElementException si vous essayez de lire un
entier et qu’il n’y en a plus dans le flot. Les clauses try et catch vous
permettent d’endiguer l’effet de cette exception et de faire le traitement
approprié.
Lorsqu’il manque des entiers, votre nuage de points devrait simplement
contenir moins de points, pour l’instant.
Ensuite, une autre condition gênante peut survenir lorsque vous lisez des
points : on peut avoir écrit deux fois les mêmes coordonnées. Votre nuage
ne devrait pas contenir des duplications.
Pour éviter les duplications, vous devez être capable de comparer deux
points. Le comparateur (==) ne réalise pas une comparaison structurelle
(soit, des deux entiers qui constituent les coordonnées). Il vous produira un
résultat positif uniquement si les deux objets Point sont effectivement les
mêmes (en termes d’emplacement dans la mémoire). Deux points identiques
du point de vue de leurs valeurs ne le sont pas du point de vue de l’opérateur
==.
Cependant, ils peuvent l’être du point de vue de la méthode equals. Chaque
classe hérite de la méthode equals (définie dans la classe Object). Celle-ci ne
fait que == présentement, alors vous devez en faire une surcharge pour votre
classe Point qui va comparer les coordonnées X et Y des deux points
concernés pour déterminer s’ils sont égaux.
Lorsque vous lisez votre nuage de points et que vous trouvez un point qui est
déjà dans le nuage, ne l’ajoutez pas une seconde fois. Plusieurs des
structures de données des Collections java supportent directement la
méthode contains(), qui vous permet de vérifier si un élément est déjà dans
votre structure. Cette fonction utilise la méthode equals reliée à la classe des
objets qui se trouvent dans la structure.
Exercice 7 : Abstraction et nettoyage
Vos classes Point, Ligne et NuagePoints ont plusieurs choses en commun. De
plus, si vous désirez changer le type d’objet que le PanneauDessin affiche,
vous devez procéder à plusieurs modifications dans les classes Labo1Main et
PanneauDessin. C’est un problème de couplage : ces classes doivent
connaître le type d’objet à dessiner pour arriver à faire leur travail, mais il est
possible d’éviter qu’il en soit ainsi.
Écrivez une classe abstraite Dessin qui représente n’importe quel objet que
vous allez pouvoir dessiner. Du point de vue des classes Labo1Main et
PanneauDessin, un objet dessinable n’a besoin d’offrir que seulement deux
méthodes : dessiner et lire. Vos trois classes Point, Ligne et NuagePoints
devraient être des descendantes de la classe Dessin.
Vous pouvez maintenant modifier les classes Labo1Main et PanneauDessin
une bonne fois pour toutes en utilisant le type Dessin.
Exercice 8 : Polygones
Pour arriver à dessiner un polygone, on a besoin d’une combinaison des
fonctionnalités des classes NuagePoints et Ligne.
Un polygone a besoin d’une liste de points qui représentent les sommets,
puis, pour effectuer le dessin, il faut tracer des lignes entre ces sommets,
mais pas toutes les lignes possibles! De plus, on aurait tendance à essayer,
avec une liste de points quelconque, d’ordonnancer la liste de points afin de
produire un polygone qui relie les sommets dans un ordre qui fonctionne
bien.
Vous devez vous demander quel type de lien existe entre le polygone, le
nuage de points et la ligne. Héritage, composition ou coopération? Bien
entendu, un Polygone est un Dessin!
Exercice 9 : Dessins composés
Afin d’arriver à produire des résultats intéressants, il faudrait pouvoir
spécifier des dessins complexes : plusieurs polygones, plusieurs lignes,
plusieurs points, etc.
Avant même de coder le polygone, vous pouvez travailler sur ce numéro et
arriver à spécifier des polygones avec les fonctionnalités développées ici.
Un DessinCompose est un Dessin qui est une liste d’autres Dessins. Dessiner
une liste de dessins ne devrait pas être top difficile...
Lire une dessin composé, par contre, est un peu plus difficile. Si votre fichier
d’entrée comprend des informations qui décrivent des lignes, des points et
des nuages de points, il est difficile de savoir à quel type d’objet la prochaine
valeur entière est associée!!
Comme notre méthode de lecture favorite ne travaille qu’avec des entiers,
on peut utiliser des valeurs entières qui n’ont pas de sens en terme de
coordonnées sur un canevas pour indiquer quel sera le type de dessin qui
sera lu, dans le contexte où notre fichier contient une liste de dessins de
types différents.
Voici donc les codes qu’on devrait utiliser :
-1 : les entiers qui suivent définissent un Point
-2 : les entiers qui suivent définissent une Ligne
-3 : les entiers qui suivent définissent un NuagePoints
-4 : les entiers qui suivent définissent un Polygone
Remarque et réflexion
Il est important de remarquer que le code de votre dessin composé va
comprendre des fonctionnalités semblables à votre liste de points. Observez
la parenté entre les deux et réfléchissez à ce que vous pourriez faire pour
éliminer le code redondant. Est-ce possible?
Exercice 10 : Polygones avec vérifications
Il est probable que vous allez devoir ajouter une capacité à votre nuage de
points : le trier.
Les algorithmes de tri sont déjà implantés dans les Collections java; pour les
utiliser, vous devez simplement vous conformer à certaines règles.
Les éléments qui peuplent votre structure de données doivent être des
descendants de Comparable.
Comparable est une interface; elle ne fait que dicter à ses descendants qu’il
devront implanter la méthode compareTo.
La méthode [Link](b) devrait retourner un nombre inférieur à zéro si
a<b, égal à 0 si a==b, et supérieur à zéro si a>b.
Votre critère pour ordonnancer les points dépend de ce que vous croyez qui
va fonctionner pour ordonnancer une liste de points dans le but de la
parcourir comme si ces points étaient les sommets d’un polygone et qu’on
désirait les relier par des lignes.
Par exemple, vous pouvez considérer que vous allez, plus ou moins, obtenir
un polygone valide si les sommets sont en ordre de coordonnée Y, et que
l’ordre de la coordonnée X n’importe pas. Ceci impliquerait de parcourir les
sommet de haut en bas, et permet de spécifier un polygone comme ceci, par
exemple :
(300,200)
(400,200)
(400,300)
(300,300)
Ce nuage ordonnancé ainsi produirait un carré 100x100, par exemple.
Cependant, il est probable que le tri selon une seule coordonnée fonctionne
mal, ou même, selon les deux coordonnées.
L’ordre dans lequel les points sont entrés peut importer également.
Si vous voulez tenir compte de l’ordre d’entrée, alors vous pouvez créer un
nouveau type de point (PointOrdonnance) qui tient compte de son ordre de
lecture. Ceci implique l’utilisation de variables de classe (mot-clé static).