:: Enseignements :: ESIPE :: E3INFO :: 2018-2019 :: Programmation Objet avec Java ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Examen INFO1 - Programmation Objet Java
|
Cette épreuve est constituée d'une partie de questions de cours
(pour un tiers des points), auxquelles vous répondrez de manière
concise (maximum 4 ou 5 lignes par question) dans un fichier
question_cours.txt, et d'une partie de programmation (les exercices
suivants pour environs deux tiers des points) pour laquelle vous
devrez écrire des classes Java. Ces deux parties sont indépendantes,
mais les exercices de programmation se suivent.
Tout ce que vous devez rendre doit être situé dans le
répertoire EXAM qui existe à la racine de votre compte; tout ce qui n'est
pas dans ce répertoire à la fin de l'épreuve sera perdu (vous aurez 0).
Il vous est conseillé d'utiliser Eclipse, et de créer un nouveau projet Java en
décochant la case "Use default location" et en spécifiant plutôt ce répertoire
EXAM;
ainsi, toutes vos sources et classes seront récupérées.
Questions de cours (6,5 points)
Exercice 1 - Constructeur (2 points)
- Quel intérêt présente la notion de "constructeur" en Java (par opposition
à une méthode d'inititalisation de structure comme on peut en écrire en C par
exemple)?
- Pourquoi dit-on, lorsque plusieurs constructeurs surchargés existent
au sein d'une même classe, qu'il faut si possible qu'il en existe un "plus général"
auquel les autres font appel?
- A quoi peut servir une classe dont tous les constructeurs sont private?
Quels problèmes cela pose-t-il?
Exercice 2 - Mais à quoi ça sert? (1 point)
Donnez un exemple (pas trop compliqué) dans lequel le polymorphisme est utile/pratique?
Exercice 3 - Comment choisir? (2 points)
Pouvez vous expliquer brièvement dans quel cas on utilise l'héritage entre classes et dans quel
cas on utilise plutôt l'implémentation d'interface? Comment utilise-t-on les classes abstraites
le plus souvent? Donnez quelques arguments pour étayer vos réponses avec quelques avantages et inconvénients.
Exercice 4 - Listes (1,5 points)
-
En fonction des usages que vous souhaitez faire d'une liste, comment
choisissez vous entre une LinkedList et une ArrayList ?
Expliquez vos critères de choix.
-
Quel est le problème du code de la méthode print ci-dessous, qui doit afficher chaque
élément de la liste, un par ligne?
void print(List<String> list) {
for(int i=0; i<list.size(); i++) {
System.out.println(list.get(i));
}
}
Par quel code faudrait-il le remplacer?
Programmation (13,5 points)
Vous vous attacherez à toujours mettre les champs avec des modificateurs d'accessibilité
les plus restreints possibles, et à factoriser le code au maximum, de sorte d'éviter autant
que possible toute duplication de code. Vous écrirez toutes les classes dans
un package nommé fr.upem.postal. Vous devez tester toutes les méthodes demandées et vous
écrirez tous vos tests dans la classe Test de ce package.
Exercice 1 - Adresse postale (2 points)
Nous considérons qu'une adresse postale, pouvant être utilisée comme destinataire
d'un envoi postal, est représentée par la classe
Address avec les quatre
champs suivants, tous de type
String, et tous fixés une fois pour toute
lors de la création de l'objet à une valeur différente de
null (ils ne peuvent pas changer au cours de la vie de l'adresse) :
-
Créez la classe Address et ajoutez-y juste ce qu'il faut pour que le
code suivant (à mettre dans la méthode main d'une classe Test)
fonctionne et affiche comme indiqué dans les commentaires:
Address dudu = new Address("Duris", "Copernic", "77454", "FRANCE");
System.out.println(dudu); // Duris Copernic 77454 FRANCE
Address bobo = new Address("Borie", "Copernic", "77454");
System.out.println(bobo); // Borie Copernic 77454 FRANCE
L'affichage doit indiquer chacun des champs dans l'ordre séparés par un espace.
Lorsque le constructeur ne spécifie pas le pays, comme dans le cas de
la variable bobo ci-dessus, l'objet sera créé avec
la chaîne "FRANCE" en guise de champ country.
-
Ajouter une méthode getCountry() permettant de connaître la
valeur du champs country(). Testez avec
System.out.println(dudu.getCountry()); // FRANCE
System.out.println(bobo.getCountry()); // FRANCE
Exercice 2 - Envois postaux (5 points)
On souhaite pouvoir gérer différents types d'envois postaux (de type
Delivery),
sachant que pour l'instant seuls deux cas concrets nous intéressent (d'autres cas concrets pourront être ajoutés
à l'avenir):
- d'une part les colis (type Parcel) qui sont définis par une adresse
de destinataire (recipient) de type Address différente de null,
un poids (weight) positif en grammes de type int et
un volume (volume) positif en cm3 de type int,
- d'autre part les lettres (type Letter) qui sont définies par une
adresse de destinataire (recipient) de type Address différente de null et
un poids (weight) positif en grammes de type int.
Ces deux types d'envois postaux peuvent être éventuellement caractérisés comme "urgent" à
leur création, mais par défaut ils ne le sont pas.
Trois méthodes doivent être disponibles sur les objets de type
Delivery:
-
getRecipient() qui retourne le destinataire;
-
isUrgent() qui retourne true si l'envoi est urgent
et false sinon;
-
price() qui retourne le prix d'affranchissement de cet envoi (un entier en centimes d'euros);
Le prix d'affranchissement d'une lettre est de 70 cents jusqu'à 20g; au delà,
il est de 1 euro plus un dixième du poids en gramme (par exemple 1,34€ pour
une lettre de 348 grammes). Si la lettre est urgente, c'est 1€ de plus.
Le prix d'affranchissement en centimes d'euros d'un colis est la somme
de son poids et de son volume. Si le colis est urgent, le prix est le double.
Proposez une implémentation en Java des différents types ci-dessus (vous
pouvez en créer d'autres) qui vous semble respecter les critères de la programmation
objet et de la factorisation de code, de sorte que le code suivant, à coller à
la suite de votre méthode
main de la classe
Test, se comporte comme
indiqué dans les commentaires:
Delivery p4D = new Parcel(dudu, 200, 1000);
System.out.println(p4D.price()); // 1200
System.out.println(p4D.getRecipient()); // Duris Copernic 77454 FRANCE
System.out.println(p4D.isUrgent()); // false
Delivery p4DU = new Parcel(dudu, 200, 1000, true);
System.out.println(p4DU.price()); // 2400
Delivery l4B = new Letter(bobo, 40);
System.out.println(l4B.price()); // 104
Delivery l4BU = new Letter(bobo, 40, true);
System.out.println(l4BU.getRecipient()); // Borie Copernic 77454 FRANCE
System.out.println(l4BU.isUrgent()); // true
System.out.println(l4BU.price()); // 204
Ajoutez les méthodes nécessaires qui permettent d'afficher les caractéristiques de
chaque type d'envoi postal comme illustré en commentaire dans le code ci-dessous; respectez
le format indiqué, c'est à dire "[URGENT] " si c'est urgent, puis "To: " suivi du
destinataire, puis "Parcel" avec le poids et le volume ou "Letter" et le poids, selon le cas:
System.out.println(p4D);
// To: Duris Copernic 77454 FRANCE: Parcel 200g 1000cm3
System.out.println(p4DU);
// [URGENT] To: Duris Copernic 77454 FRANCE: Parcel 200g 1000cm3
System.out.println(l4B);
// To: Borie Copernic 77454 FRANCE: Letter 40g
System.out.println(l4BU);
// [URGENT] To: Borie Copernic 77454 FRANCE: Letter 40g
Exercice 3 - Bureau de poste (6,5 points)
La classe PostOffice représente un bureau de poste auprès duquel les
clients enregistrent des envois postaux avec la méthode register(Delivery delivery)
qui retourne le prix d'affranchissement, en centimes d'euros, à payer par le client.
Le bureau de poste stocke chaque envoi postal ainsi enregistré dans une liste.
-
Écrire la classe PostOffice et sa méthode
int register(Delivery delivery)), ainsi qu'une méthode affichant le contenu
de la liste, comme dans le code ci-dessous (vous n'avez pas besoin de gérer les
retours à la ligne comme dans l'exemple: ils ont été mis dans le commentaire pour
des raisons de mise en page).
PostOffice po = new PostOffice();
po.register(p4D);
po.register(p4DU);
po.register(l4B);
po.register(l4BU);
System.out.println(po);
// [To: Duris Copernic 77454 FRANCE: Parcel 200g 1000cm3,
// [URGENT] To: Duris Copernic 77454 FRANCE: Parcel 200g 1000cm3,
// To: Borie Copernic 77454 FRANCE: Letter 40g,
// [URGENT] To: Borie Copernic 77454 FRANCE: Letter 40g]
-
Pour vérifier sa caisse en cours de journée, le postier aimerait disposer
d'une méthode int totalPrice() qui retourne la somme des prix des
envois postaux qui ont été enregistrés. Implémentez cette méthode avec une
solution performante en terme de complexité au cas où le postier vérifierait
fréquemment sa caisse.
-
On veut maintenant une méthode
List<Delivery> deliveriesForRecipient(Address recipient) dans
la classe PostOffice, qui retourne
la liste des envois postaux enregistrés dans ce bureau qui sont à destination
de l'adresse passée en argument. Testez avec le code suivant:
System.out.println(po.deliveriesForRecipient(new Address("Borie", "Copernic", "77454")));
// [To: Borie Copernic 77454 FRANCE: Letter 40g,
// [URGENT] To: Borie Copernic 77454 FRANCE: Letter 40g]
-
On voudrait pouvoir utiliser le type PostOffice dans une boucle à
la manière suivante:
for(Delivery d : po) {
if(d.isUrgent()) {
System.out.println("Urgent delivery for " + d.getRecipient());
}
}
Faites le nécessaire pour que ce code fonctionne.
-
On veut enfin doter la classe PostOffice d'une méthode
void sortDeliveries(Comparator<? super Delivery> c) qui,
à la manière de la méthode sort() sur les listes, accepte un comparateur
pour trier les envois postaux du bureau de poste en fonction de critères spécifiques.
Écrire cette méthode et testez-la depuis le main en lui passant une lambda expression
qui demande un tri par ordre croissant des prix:
po.sortDeliveries(/* a vous d'écrire la lambda qui compare sur les prix */);
// la liste des envois postaux doit ensuite être triée du moins cher au plus cher
Ensuite, faites en sorte que si le comparateur passé en argument vaut null
alors la méthode sortDeliveries trie la liste des envois postaux selon
l'ordre naturel des colis, qui repose sur l'ordre naturel des
destinataires de type Address, à savoir, l'ordre lexicographique
des pays (country), puis des code postaux (zip), puis du détail
de l'adresse et enfin du nom. A destinataire égal, on classera en premier les envois
urgents.
po.sortDeliveries(null);
// la liste des envois postaux doit être triée par destinataire (Borie avant Duris),
// puis les urgents avant les non urgents
© Université de Marne-la-Vallée