TP Java 3

Transcription

TP Java 3
Master 2 BBSG
POO, langage Java
Laurent Tichit
3. Héritage
1. Une bibliothèque
2. Polygones
3. Héritage ou composition ?
3.1. Une bibliothèque
Pour la gestion d’une bibliothèque on nous demande
d’écrire une application traitant des documents de nature
diverse : des livres, qui peuvent être des romans ou des
manuels, des revues, des dictionnaires, etc.
Tous les documents ont un numéro d’enregistrement (un
entier) et un titre (une chaîne de caractères). Les livres ont,
en plus, un auteur (une chaîne) et un nombre de pages (un
entier). Les romans ont éventuellement un prix littéraire (un
entier conventionnel, parmi : GONCOURT, MEDICIS,
INTERALLIE, etc.), tandis que les manuels ont un niveau
scolaire (un entier). Les revues ont un mois et une année
(des entiers) et les dictionnaires ont une langue (une chaîne
de caractères appartenant à un ensemble prédéfini, comme
"anglais", "allemand", "espagnol", etc.).
Tous les divers objets en question ici (livres, revues,
dictionnaires, romans, etc.) doivent pouvoir être
manipulées en tant que documents.
A. Définissez les classes Document, Livre, Roman, Manuel, Revue et Dictionnaire, entre
lesquelles existeront les liens d’héritage que la description précédente suggère.
Dans chacune de ces classes définissez
• le constructeur qui prend autant arguments qu’il y a de variables d’instance et qui se limite à
initialiser ces dernières avec les valeurs des arguments,
• une méthode public String toString() produisant une description sous forme de chaîne
de caractères des objets,
• si vous avez déclaré private les variables d’instance (c’est conseillé, sauf indication contraire )
définissez également des « accesseurs » publics get... permettant de consulter les valeurs de ces
variables.
Écrivez une classe exécutable TestDocuments qui crée et affiche plusieurs documents de types
différentes.
B. Une bibliothèque sera représentée par un tableau de documents (on verra un autre jour de meilleures
manières de faire, basées sur l’emploi d’une Collection). Définissez une classe Bibliotheque,
avec un tel tableau pour variable d’instance et les méthodes :
• Bibliotheque(int capacité) - constructeur qui crée une bibliothèque ayant la capacité
(nombre maximum de documents) indiquée,
• void afficherDocuments() - affiche tous les ouvrages de la bibliothèque,
• Document document(int i) - renvoie le ième document,
• boolean ajouter(Document doc) - ajoute le document indiqué et renvoie true
(false en cas d’échec),
• boolean supprimer(Document doc) - supprime le document indiqué et renvoie true
(false en cas d’échec)
• void afficherAuteurs() - affiche la liste des auteurs de tous les ouvrages qui ont un
auteur (au besoin, utilisez l’opérateur instanceof)
C. Définissez, avec un effort minimal, une classe Livrotheque dont les instances ont les mêmes
fonctionnalités que les Bibliotheques mais sont entièrement constituées de livres. Comment
optimiser dans la classe Livrotheque la méthode afficherAuteurs ?
3.2 Polygones
Pour cet exercice vous devez disposer d’une classe Point avec – au moins – deux membres d’instance
privés x et y de type double (par exemple), un constructeur public Point(double x, double
y), des accesseurs public double x() et public double y() et l’habituelle transformation
en chaîne de caractères public String toString(). La classe Point définie à la série
précédente devrait faire l’affaire.
A. Définissez une classe Polygone comportant la variable membre :
• protected Point[] sommets – tableau contenant les sommets du polygone
et les méthodes :
• public Polygone(Point[] sommets) – construction d’un polygone à partir du tableau
de ses sommets
• protected Polygone(int nbrSommets) – début de la construction d’un polygone à
partir du nombre de ses sommets ; ces derniers restent indéterminés (ou plutôt valent null) et
devront être donnés ultérieurement
• public Point getSommet(int i) – obtention du ième sommet du polygone
• public double aire() – calcul de la surface du polygone (voir indications ci-dessous)
• public String toString() – expression textuelle du polygone ; par exemple
"[(1.0,1.0),(5.0,1.0),(3.0,2.0)]"
B. Définissez une classe Triangle, sous-classe de Polygone, avec un constructeur
• public Triangle(Point a, Point b, Point c) – construction du triangle ayant les
trois sommets indiqués
C. Définissez une classe Rectangle (sous-entendu, avec des côtés parallèles aux axes), sous-classe de
Polygone, munie d’un constructeur
• public Rectangle(double xMin, double xMax, double yMin, double
yMax) – construction d’un rectangle parallèle aux axes
D. Définissez une classe PolygoneRegulier, sous-classe de Polygone, disposant d’un constructeur
• public
PolygoneRegulier(Point
centre,
double
rayon,
int
nombreSommets) – construction du polygone régulier ayant le centre, le rayon et le nombre de
sommets indiqués.
E. Écrivez une classe TestPolygone avec une méthode main construisant et affichant des polygones
de diverses sortes et permettant de vérifier que la méthode aire est correcte.
Voyez-vous pourquoi certains membres de la classe Polygone ont été déclarés protected au lieu de
private ? Aurions-nous pu faire autrement ?
Indications, 1. Voici une manière de calculer l’aire S d’un polygone ayant les sommets (x0, y0), (x1, y1), ...
(xn-1, yn-1) :
S = ½ | (x0 + x1) × (y0 – y1) + (x1 + x2) × (y1 – y2) + ... + (xn – 2 + xn – 1) × (yn – 2 – yn – 1) + (xn – 1 + x0) × (yn – 1
– y0) |
Indications, 2. Les sommets (xi, yi) d’un polygone régulier qui a n sommets, le point (xc, yc) pour centre, r
pour rayon et un sommet ayant yc pour ordonnée, sont donnés par :
xi = xc + r × cos (2 × pi × i / n) ; yi = yc + r × sin (2 × pi × i / n)
3.3 Héritage ou composition ?
Prérequis. Si vous ne l’avez pas encore fait, jetez un œil sur la documentation de la classe
java.util.ArrayList. Une arraylist (ou un vector) AL se comporte comme un tableau T, c’est-àdire qu’elle offre l’accès indexé optimisé (on dit « en temps constant ») à ses éléments, sauf qu’au lieu de
« x = T[i] » il faut écrire « x = AL.get(i) » et au lieu de « T[i] = x » il faut écrire
« AL.set(i,x) ». Cependant, une arraylist a un avantage considérable sur un tableau : elle s’occupe de
l’allocation de son espace mémoire, l’augmentant lorsque c’est nécessaire, sans que le programmeur ait à
s’en soucier.
Exercice. Un journal est une collection d’événements. Un événement est fait de deux champs : une date et
un texte. Un journal doit posséder les opérations suivantes :
• unJournal.ajouter(unTexte) – ajout au journal d’un événement composé de la date courante
(que cette méthode obtient automatiquement) et du texte indiqué
• unJournal.toString() – renvoie une chaîne de caractères contenant tous les événements du
journal
• unJournal.toString(uneChaine) – renvoie une chaîne de caractères contenant tous les
événements dont le texte contient la chaîne indiquée
N.B. Pour les dates, revoyez si nécessaire l’exercice 3 de la série 1.
A. Écrivez une classe Evenement et une classe Journal. On fera en sorte que la classe Evenement,
soit une classe interne à Journal (une classe interne est simplement une classe définie à l'intérieur d'une
autre classe. On se sert des classes internes pour ne pas polluer l'espace de noms. Généralement, seule la
classe appelante y accède, bien qu'une classe interne ne soit pas forcement private). Evenement
sera aussi simple que possible (les deux champs indiqués, un constructeur élémentaire et la méthode
toString habituelle).
Dans cette question, la classe Journal doit être une sous-classe de java.util.ArrayList.
B. Écrivez une classe TestJournal avec une méthode main simple qui lit et exécute des commandes
comme :
+ texte
ajout au journal de l’événement ayant le texte indiqué
?
listage de tous les événements du journal
? chaîne
listage des événements qui contiennent la chaîne indiquée
*
abandon du programme
C. Réécrivez la classe Journal mais, au lieu d’en faire une sous-classe de ArrayList mettez-y un
membre de type ArrayList. La classe TestJournal doit fonctionner sans changement.
D. Etre ou avoir ? Dans la question A vous avez lié les classes ArrayList et Journal par un lien
d’héritage : un objet Journal « est » un objet ArrayList ; dans la question C vous les avez liés par
un lien de composition : un objet Journal « a » un objet ArrayList. D’après vous, quels sont les
mérites de l’une et l’autre manière de faire?
Dans quel cas contrôlez-vous mieux le comportement d’un objet Journal ? Supposez qu’on vous
demande d’interdire les suppressions d’événements du journal ; est-il facile d’obtenir cela dans la solution
A?
Voyez-vous dans quelle situation l’héritage peut-il devenir préférable, voire nécessaire ?