:: Enseignements :: Licence :: L3 :: 2025-2026 :: Programmation Objet avec Java ::
![[LOGO]](http://monge.univ-eiffel.fr/ens/resources/mlv.png) |
Héritage, appel de constructeurs, visibilité
|
Exercice 1 - Gifted
Le but de ce TP est de faire deux implantations des mêmes classes,
une en utilisant l'héritage et l'autre en utilisant les interfaces et le pattern-matching.
L'idée est de montrer qu'il est possible d'utiliser l'héritage,
mais que c'est plus compliqué que d'utiliser les interfaces.
Pour tous le TPs, vous avez un petit code qui vous indique comment utiliser les classes
et méthodes que l'on va vous demander d'écrire.
Ces tests, doivent compiler et fonctionner !
static void main() {
// Q1
var gift = new Gift("cake", 10);
IO.println(gift.price()); // 10
// Q2
//new Gift("cake", -2); // exception
//new Gift(null, 2); // exception
// Q3
IO.println(gift); // Gift { name: "cake", basePrice: 10 }
// Q4
IO.println(new Gift("cake", 5).equals(new Gift("cake", 5))); // true
IO.println(gift.equals("cake")); // false
// Q5
var deluxe = new Deluxe("watch", 100, "a nice gift", true);
// Q6
IO.println(deluxe); // Deluxe { name: "watch", basePrice: 100, ribbon: true }
IO.println(deluxe.price()); // 215
// Q7
IO.println(new Deluxe("watch", 80, "", false)
.equals(new Deluxe("watch", 80, "", false))); // true
IO.println(new Gift("watch", 80).equals(new Deluxe("watch", 80, "", false))); // false
IO.println(new Deluxe("watch", 80, "", false).equals(new Gift("watch", 80))); // false
// Q8
IO.println(Main.totalPrice(List.of(gift, deluxe))); // 225
// Q9
Product product1 = new Gift("teddy bear", 20);
Product product2 = new Deluxe("deluxe bear", 20, "a nice bear", true);
IO.println(Main.totalPrice(List.of(product1, product2))); // 155
// Q10
IO.println(Product.priceOf(product1)); // 20
IO.println(Product.priceOf(product2)); // 135
}
Dans le package fr.uge.giftshop, nous allons créer, incrémentalement,
les classes Gift, Delux et Main.
Pour tout ce TP, les prix sont des ints.
Le code ci-dessus correspond à la méthode main de la classe Main.
Dans un premier temps, écrire une classe cadeau (Gift), pas un record, qui contient
un nom (name en anglais) de type String et
un prix de base (basePrice en anglais) ainsi qu'une méthode price()
qui renvoie le prix.
Pour vérifier que vous avez bien écrits les préconditions pour la classe Gift,
vérifier que les appels aux constructeurs marqués "Q2" lèvent bien la bonne exception.
On souhaite afficher un Gift avec un format plus lisible.
Modifier votre implantation pour cela (attention, le format doit être exactement celui demandé).
On souhaite maintenant pouvoir savoir si deux cadeaux ont les mêmes valeurs en utilisant
la méthode equals habituelle.
Rappel: si on appel equals avec autre chose qu'un Gift, la méthode
doit renvoyée false.
Rappel 2: si on implante equals, quelle méthode doit-on aussi implanter ?
Modifier la classe en conséquence.
On souhaite créer une classe Deluxe pour les cadeaux cossus,
qui ont en plus d'un nom et d'un prix de base, un message personnel
(une String) ainsi qu'optionnellement un ruban
(hasRibbon de type boolean).
Le prix est calculé en utilisant le prix de base plus 10 fois
le nombre de caractères du message personnel plus 5 s'il y a un ruban.
Comme c'est un TP sur l'héritage, Deluxe hérite de Gift.
Oui, c'est une mauvaise idée, mais le but du TP est de montrer que c'est une mauvaise idée.
Comment doit-on déclarer la classe Deluxe ?
Comment doit-on écrire le constructeur ?
Note: en Java 25, on peut mettre les tests des préconditions avant l'appel au constructeur
de la super-classe.
On peut voir que le code que nous avons écrit est farci de bugs,
en effet, l'affichage et la méthode price() ne font pas ce qui est demandé.
Comment doit-on corriger la classe Deluxe ?
Faites les changements qui s'impose !
Attention, il est interdit d'ajouter des méthodes publiques en plus des méthodes
demandées que cela soit dans la classe Deluxe ou dans la classe Gift.
On peut se rendre compte que le equals ne fonctionne pas non plus ?
Comment doit-on corriger le problème ?
Pour simplifier une partie de l'écriture, on va déclarer la classe Deluxe final.
En quoi cela simplifie le code ?
Faire en sortes que les tests correspondant à Q7 fonctionnent.
Écrire dans la classe Main une méthode totalPrice
qui prend en paramètre une liste contenant des Gift et des Deluxe
et renvoie la somme des prix.
L'implantation de totalPrice doit utiliser un stream !
Commenter le code des classes Gift et Deluxe, et réécrivez celles-ci
sous forme de record en introduisant une interface Product.
Modifier le code de totalPrice pour que le code de la méthode main continue
de fonctionner
Pourquoi avez-vous besoin d'une interface Product ?
Enfin, au lieu d'utiliser le polymorphisme pour la méthode price,
on souhaite utiliser le pattern-matching, pour cela créer dans Product
une méthode statique priceOf qui utilise le pattern-matching
pour calculer les prix.
On souhaite de plus, supprimer la méthode price() écrite
dans deluxe, comment faire pour que le main
continue de fonctionner.
Enfin, pour les plus balèzes, on ajoute dans
Main
une méthode
bestSeller qui renvoie le nom
des produits qui a fait le plus de vente.
static void main() {
...
// Q12
IO.println(Main.bestSeller(List.of(deluxe, product1, product2, product2))); // Optional[bear]
}
Dans notre exemple, "bear" a été vendu pour 290 et "watch" pour 215.
© Université de Marne-la-Vallée