:: Enseignements :: Master :: M1 :: 2021-2022 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Rappel de notions de programmation objet
|
Pour l'ensemble des TDs de cette année, nous allons utiliser l'IDE Eclipse
(pas de problème si vous voulez en utiliser un autre pourvu qu'il sache
faire de la complétion automatique et du refactoring).
Eclipse s'exécute en tapant dans un terminal :
eclipse-light
Après démarrage, vérifiez que vous utilisez le bon JDK : dans Window > Preferences > Java > Installed JREs et
assurez-vous que la version est bien compatible avec Java 17.
Puis vérifiez que le compilateur a bien été configuré en mode 17 :
dans Window > Preferences > Java > Compiler, le Compiler compliance level doit être à 17.
Pour la dernière question (optionnelle), nous allons utiliser le switch sur des types
qui est une preview feature, il faudra donc aussi activer cette option au niveau du compilateur.
Enfin, lorsque vous créez un projet, Eclipse vous propose de créer un module, déclinez poliment pour l'instant
(sinon les tests ne marcheront pas), nous verrons dans un prochain TP ce qu'est un module.
Chaque exercice vient avec des tests unitaires
JUnit
qui vous permettent de vérifier que votre implantation passe les tests.
JUnit requiert des JARs qui ne sont pas installés dans votre projet Java
par défaut.
Le plus simple est de créer un test JUnit (New -> JUnit Test),
de sélectionner JUnit 5 (JUnit Jupiter) et de laisser faire Eclipse qui vous proposera
d'installer les JARs JUnit 5.
L'autre solution est d'associer la librarie JUnit dans le build path du projet.
bouton droit -> Properties -> Java Build Path -> Add Library -> JUnit -> JUnit Jupiter
Attention, les JARs de JUnit doivent être installé dans le
Classpath et pas dans
le
ModulePath.
Exercice 1 - Location de voitures
Le but de cet exercice est de créer un ensemble de classes permettant
de gérer une agence de location de voitures.
-
Écrire un record Car dans le package fr.umlv.rental,
correspondant à un véhicule qui pourra être loué.
Un véhicule est décrit par un modèle (une chaîne de caractères) ainsi
qu'une année de fabrication.
Par exemple, une Ford Mustang sera créée de cette façon :
Car mustang = new Car("ford mustang", 2020);
On veut de plus empêcher de créer de voiture ayant un modèle null.
Pour tester si une valeur est null, vous utiliserez la méthode
Objects.requireNonNull().
Vérifiez que votre code passe les tests unitaires étiquetés "Q1". Ne passez pas à la question suivante tant que tous les tests ne sont pas verts. Un test réussi ne signifie pas que le code est correct, mais un test raté garantit qu'il y a un problème.
-
Modifier le record Car pour que le code suivant affiche
le texte "ford mustang 2020".
System.out.println(mustang);
-
Créer une classe CarRental (toujours dans le package fr.umlv.rental)
qui stocke les véhicules qui peuvent être loués dans une liste.
La classe CarRental doit posséder une méthode add qui permet d'ajouter
un véhicule dans la liste.
Faire en sorte que la liste ne puisse pas contenir null en empêchant d'ajouter
des voitures null.
-
Pour visualiser une instance de la classe CarRental,
on devra afficher l'ensemble des véhicules de la liste, séparés
par des retours à la ligne (mais sans retour à la ligne final !).
Écrire le code correspondant en utilisant la classe StringBuilder.
-
Rappeler à quoi sert l'interface
Stream en Java,
comment obtenir un stream à partir d'une liste, comment marchent les méthodes filter,
map et collect et enfin comment peut-on utiliser le collecteur
Collectors.joining()
pour simplifier l'implantation de la méthode d'affichage que vous venez d'écrire.
-
Écrire une méthode remove qui permet de retirer un véhicule de la liste.
Que faire si le véhicule n'a pas été préalablement ajouté ?
Quelle est la méthode de Car appelée par CarRental.remove() qui
fait en sorte que le code ci-dessous fonctionne ?
Rappel: slide 14 du cours de l'année dernière
@Test @Tag("Q6")
public void shouldRemoveCarOfRental() {
var rental = new CarRental();
rental.add(new Car("ford mustang", 2013));
rental.remove(new Car("ford mustang", 2013));
assertEquals("", rental.toString());
}
Juste pour vérifier que vous savez l'écrire, redéfinir cette méthode (et celle liée) dans Car.
-
On cherche à connaître toutes les voitures enregistrées dans le CarRental
ayant la même année de fabrication.
Écrire une méthode findAllByYear(int year) qui prend en paramètre
une année et renvoie une liste des voitures ayant l'année de fabrication demandée.
Que doit-on faire si il n'y a pas de voiture correspondant à l'année demandée.
Note: il existe une méthode toList() sur l'interface Stream !
-
L'application que vous développez doit aussi être vendue en Egypte où
malheureusement, il n'est pas rare de manquer d'essence.
Pour éviter de mettre la clé sous la porte, les loueurs de voitures
ont trouvé une solution de secours en louant aussi des chameaux.
Modifier le code de votre application pour permettre de louer non
plus uniquement des véhicules mais aussi des chameaux, sachant
qu'un chameau possède juste une date de naissance et que son affichage
est "camel" suivi d'un espace et de sa date de naissance.
Par exemple, le code suivant devra fonctionner
var rental = new CarRental();
rental.add(new Car("ford mustang", 2014));
rental.add(new Camel(2010));
La méthode findAllByYear devra renvoyer une liste pouvant être constituée
de véhicules et de chameaux.
En terme de design, faire en sorte que si l'on
doit ajouter plus tard une classe SpaceShuttle pour gérer les navettes
spatiales, alors on n'aura pas à modifier la classe CarRental.
-
Les véhicules à louer doivent être assurés.
Une voiture de moins de 10 ans coûte 200 euros à assurer et sinon, l'assurance est de 500 euros.
Pour un chameau, le prix de l'assurance est proportionnel à son âge, qu'il faut multiplier par 100 euros..
Écrire dans la classe CarRental, une méthode insuranceCostAt
qui permet de calculer le coût total pour assurer tous les véhicules pour une année donnée
(passée en paramètre).
Attention, l'hypothétique introduction de la classe SpaceShuttle dont le prix d'assurance
sera calculé en fonction du nombre de voyages effectués devra aussi se faire sans
modifier la classe CarRental.
Note : pensez à gérer le cas où la date est plus ancienne que l'année ce création du véhicule ou
de naissance des chameaux.
Note 2 : attention à ne pas dupliquer de code.
-
Si Car et Camel étaient des classes et non pas des records, serait-il vraiment nécessaire d'utiliser une interface ?
-
Enfin, écrire dans la classe CarRental,
une méthode findACarByModel qui permet de trouver une voiture
à partir de son modèle passé en paramètre.
Expliquer de plus pourquoi cette méthode doit retourner
un objet de type Optional.
-
Optionnellement, pour les plus balèzes, on peut utiliser du pattern matching (un switch sur les instances) pour implanter la méthode findACarByModel de façon plus simple.
Faire un switch sur des objets est une preview feature, il faut l'activer dans les options
du compilateur.
Après, on peut écrire
Object o = ...
switch(o) {
case Foo foo -> ...
case Bar bar -> ...
default -> ...
}
Fournir une autre implantation de findACarByModel utilisant le pattern matching.
Enfin, comment faire pour éviter d'avoir un default dans le case (indication, on va déclarer
l'interface sealed). Et pour c'est une bonne pratique lorsque l'on utilise le pattern matching ?
© Université de Marne-la-Vallée