Travaux Pratiques n°3
Table des matières
Objectifs (1h30)
- Savoir implanter la notion d'interface en Java
- Comprendre la différence entre héritage et délégation
- Savoir utiliser les classes paramétriques
Rendu du travail
Le TP doit être rendu en fin séance, quel que soit son état d'avancement. Envoyez le source des classes (.java) ainsi que les classes compilées (.class) dans une archive zip (voir les instructions du TP1b et veiller à bien ajouter les sources !) à Gauthier Picard la fin, avec comme sujet [LCPOO] TP3 <nom1> <nom2>. L'absence d'envoi sera sanctionnée dans la note finale.
Classes abstraites et interfaces : exemple des collections
Nous avons vu en TD les notions de classes abstraites et
d'interfaces. En UML les classes et méthodes abstraites sont
indiquées avec le mot {abstract}
ou leur nom écrit en
italique. Les interfaces sont indiquées par {interface}
ou <<interface>>
.
Ces notions sont très usitées dans les librairies fournies avec Java.
Notamment, les collections, que vous avez déjà utilisées en sont un bon
exemple. Le schéma suivant présente une partie des héritages et des
implémentations à partir de la classe concrète ArrayList<E>
(notons qu'un type passé en paramètre d'une classe est noté par
un rectangle en haut à droite de la classe).
En partant de ArrayList
, nous pouvons constater :
ArrayList
hérite de la classe abstraiteAbstractList
et implémente donc les méthodesget
etsize
qui sont abstraites dansAbstractList
.AbstractList
hérite de la classe abstraiteAbstractCollection
ce qui lui fournit notamment les méthodesadd
,remove
etsize
provenant de l'interfaceCollection
(voir ci-dessous), et implémente également l'interfaceList
qui lui fournit surtout les méthodesget
etset
pour accéder en lecture et en écriture à des éléments particulier de la liste.AbstractCollection
hérite directement de la classeObject
et implémente l'interfaceCollection
nécessitant les méthodesadd
,remove
etsize
.- L'interface
List
hérite de l'interfaceCollection
, et lui ajoute les méthodesget
etset
.
Donc par polymorphisme, une ArrayList
peut également
être utilisée comme une AbstractList
, comme une AbstractCollection
,
comme un Object
, comme une List
et comme une Collection
.
Liste triée par héritage
Généralisation de la liste triée de String
Au TP précédent, vous avez défini une liste triée de chaînes de
caractères : SortedListOfStrings
. Par héritage vous avez pu
définir qu'une liste triée est une ArrayList<String>
dont la
méthode add
est modifiée de telle sorte que la chaîne à
insérer soit à la bonne place dans la liste au lieu d'être ajoutée en
fin de liste. Sans le savoir vous avez utilisé l'interface @<tt>Comparable@</tt>
qu'implémente la classe String
de Java, en utilisant la
méthode compareTo
. Donc, votre méthode pour insérer une
chaîne de caractère peut être utilisée pour n'importe quelle classe
implémentant l'interface Comparable
(à quelques
modifications de déclarations près).
Exercice 1
En vous inspirant de la correction de la classe SortedListOfStrings
, écrivez une classe SortedList
permettant
de ranger n'importe quel objet à partir du moment où cet objet est
comparable aux objets contenus dans la liste (et inversement). En
d'autres termes, ceci signifie qu'au lieu de ranger des objets de type String
votre classe doit ranger des objets de type quelconque E
qui soit comparable à des objets de type E
. En Java, on
note ce type E extends Comparable<E>
comme présenté
dans le code et la figure suivants :
public class SortedList<E extends Comparable<E>> extends ArrayList<E> { ... }
Ainsi, si vous pourrez utiliser des listes contenant des types différents comme dans l'exemple suivant :
SortedList<String> sls = new SortedList<String>(); sls.add("Hello"); sls.add("World"); SortedList<Integer> sli = new SortedList<Integer>(); sli.add(1); sli.add(2);
Classe de test
Pensez à tester votre code dans une classe à part contenant une méthode main
comme dans le TP précédent. Vous pouvez vous inspirer de la classe SortedListOfStringsTest
donnée en solution du TP2.
Liste triée par délégation
Exercice 2
Dans un package de votre projet Java, écrivez la
classe SortedListUsingDelegation
utilisant la délégation au lieu de
l'héritage, comme le montre la figure suivante, en vous inspirant de la solution de la classe SortedListOfStringsUsingDelegation
.
Pour rappel, la délégation signifie simplement qu'au
lieu d'hériter de la classe ArrayList
, la classe SortedListUsingDelegation
encapsule un objet (donc possède un attribut) du type ArrayList
et le manipule pour
exhiber le comportement d'une liste. Afin d'avoir des accès à cette
liste, il faut par contre définir des méthodes.
Exercice 3
Ecrivez et testez donc les méthodes présentes dans la figure :
add
pour ajouter un élément à la bonne place,get
pour récupérer le ième élément,peek
pour récupérer le premier élement de la liste,clear
pour vider la liste,remove
pour supprimer un élément de la liste,size
pour récupérer la taille de la liste,isEmpty
pour déterminer si la liste est vide,contains
pour déterminer si un élément appartient à la liste.
Par contre, comme cela a été souligné au TP précédent, notre liste conçue par délégation n'est plus utilisable en tant que liste (pas de polymorphisme). Du coup, il n'est pas possible par exemple de l'utiliser dans un contexte de liste itérable comme le suivant :
SortedListUsingDelegation<Integer> sliud = new SortedListUsingDelegation<Integer>(); sliud.add(1); sliud.add(2); for (Integer i : sliud) //erreur à la compilation !!! System.out.println(i);
Pour résoudre ce problème, nous pouvons proposer par exemple de faire de notre SortedListUsingDelegation
une concrétisation de l'interface Iterable
, et donc utilisable dans de tels contextes. Pour être encore plus complets, nous pourrions également implémenter l'interface List
mais ceci nécessiterait de coder les 25 méthodes de cette interface.
Exercice 4
Modifiez la classe SortedListUsingDelegation
afin qu'elle implémente l'interface Iterable
. Ceci signifie qu'il faut que votre classe présente la méthode iterator()
qui doit renvoyer l'itérateur de la liste encapsulée par la classe.