Epreuve de Programmation Orientée Objet 2ème année de Licence Informatique 1er juin 2007 Durée : 3 heures. Seule la documentation des classes java.util.list et java.util.arraylist distribuée est autorisée. Ce qui est évalué : Votre capacité à : utiliser correctement le langage JAVA pour implémenter une classe ; effectuer des choix corrects pour la visibilité des champs et des méthodes ; donner l implémentation d une classe en conformité avec son interface et son contrat ; utiliser correctement l héritage et la généricité pour la définition de classes. Présentation du problème Dans le cadre de l implémentation du jeu d aventure Zork, il est nécessaire de définir la notion d objet : Certaines pièces contiennent des objets. Certains objets peuvent être emportés par le joueur, d autres non. Le joueur peut transporter des objets avec lui. Chaque objet a un poids. Le joueur ne peut transporter des objets que dans la mesure où le poids total des objets transportés ne dépasse pas une certaine limite fixée à l avance. Les pièces et les joueurs ayant en commun de pouvoir contenir des objets, on décide d implémenter ce comportement commun dans une classe générique nommée ArrayListConteneur. On décide ensuite d utiliser l héritage pour définir les classe Piece et Joueur. La documentation complète de la classe générique ArrayListConteneur figure en annexe. L implémentation des classes Piece et ObjetZork ne sera pas abordée dans le cadre de cette épreuve, la classe ObjetZork pourra cependant être utilisée dans la définition de la classe Joueur. 1 Définition de la classe ArrayListConteneur La classe générique ArrayListConteneur représente un conteneur pouvant contenir un nombre illimité d éléments. La structure de données interne utilisée pour mémoriser les objets contenus dans un conteneur est une ArrayList. Un ArrayListConteneur peut contenir plusieurs exemplaires d un même élément (au sens de cette classe, deux éléments représentent un même objet si ils sont equals ) et l ordre des éléments n est pas significatif (i.e. quelque soit l ordre dans lequel les éléments sont ajoutés, deux conteneurs contenant les mêmes éléments en même quantité seront considérés comme ayant le même contenu). Par ailleurs, un élément ne peut être ajouté à un conteneur que si cet ajout est considéré comme possible : dans ce but, la méthode ajoutpossible est définie afin de permettre de tester si les critères requis sont satisfaits par un objet donné. Exercice 1.1 Implémentation de la classe ArrayListConteneur. Donnez le code source complet de la classe ArrayListConteneur dont la documentation complète est donnée en annexe. Parmi l ensemble des méthodes figurant dans la documentation on se limitera aux méthodes suivantes : les deux constructeurs ajoutpossible(e oz) ajouter(e obj) retirer(object obj) M. Champesme Département d Informatique Institut Galilée 1
contientcombiende(object obj) getnbobjets() memecontenu(arraylistconteneur<?> c) equals(object o) clone() hashcode() 2 Implémentation de la classe Joueur On souhaite maintenant définir la classe Joueur, en réutilisant, grâce à l héritage et la généricité, les fonctionnalités définies pour la classe ArrayListConteneur. Dans le jeu Zork, un joueur est caractérisé par son nom, les objets qu il transporte avec lui dans son sac et la capacité maximale de son sac. Un joueur peut transporter dans son sac autant d objets qu il le souhaite, du moment que ces objets sont transportables (cf. méthode esttransportable() de la classe ObjetZork) et que le poids total de l ensemble des objets transportés ne dépasse pas la capacité maximale de son sac telle qu elle a été fixée à la création de cette instance de la classe Joueur. Exercice 2.1 Implémentation de la classe Joueur. Donnez le code source complet de la classe Joueur en faisant en sorte que cette classe possède toutes les caractéristiques définies dans la classe ArrayListConteneur, ainsi que les caractéristiques correspondant aux méthodes suivantes : un constructeur initialisant un Joueur ne possédant aucun objet un constructeur initialisant un Joueur possédant les objets présents dans une liste passée en paramètre (cf. constructeur analogue de la classe ArrayListConteneur une méthode String getnom() renvoyant le nom du Joueur une méthode int poidssac() renvoyant le poids total de tous les objets transportés une méthode int getmaxcapacite() renvoyant le poids maximum que ce Joueur peut transporter Vous devrez préciser sous forme de commentaires, le contrat associé au constructeur de cette classe (le contrat des autres méthodes n est pas demandé). A Documentation de la classe ArrayListConteneur<E> Voire page suivante. 2
Class ArrayListConteneur<E> public class ArrayListConteneur<E> extends java.lang.object implements java.lang.iterable<e>, java.lang.cloneable Implémentation d'un conteneur d'objets utilisant une ArrayList comme structure de données. Les éléments contenus ne sont pas ordonnés et un conteneur peut contenir plusieurs exemplaires d'un même élément (au sens de equals). Un conteneur ne peut pas contenir la valeur null. Invariant: getnbobjets() >= 0; estvide() <==> getnbobjets() == 0; (\forall E obj; ; contient(obj) <==> (contientcombiende(obj) > 0)); Constructor Summary ArrayListConteneur() Initialise un ArrayListConteneur vide. ArrayListConteneur(java.util.List<? extends E> list) Initialise un ArrayListConteneur de même contenu que la liste spécifiée. Method Summary void ajouter(e obj) Ajoute l'objet specifié à ce conteneur. void ajouter(e obj, int ncopies) Ajoute ncopies exemplaires de l'objet specifié à ce conteneur. boolean ajoutpossible(e oz) Indique si un exemplaire de l'objet spécifié peut être ajouté à ce conteneur. boolean ajoutpossible(e oz, int ncopies) Indique si ncopies exemplaires de l'objet spécifié peuvent être ajoutés à ce conteneur. ArrayListConteneur<E> clone() Renvoie un clone de ce conteneur. boolean contient(java.lang.object obj) Renvoie true si le conteneur contient au moins un exemplaire de l'objet specifié. int contientcombiende(java.lang.object obj) Renvoie le nombre d'exemplaires de l'objet specifié presents dans ce conteneur. boolean equals(java.lang.object o) Teste si l'objet spécifié est equals à ce conteneur. boolean estvide() Renvoie true si ce conteneur ne contient aucun objet.
int getnbobjets() Renvoie le nombre d'objets dans ce conteneur. int hashcode() Renvoie un code de hashage pour ce conteneur. java.util.iterator<e> iterator() Renvoie un itérateur sur les éléments de ce conteneur. boolean memecontenu(arraylistconteneur<?> c) Renvoie true si le ArrayListConteneur spécifié est non null et contient les mêmes objets (au sens de equals) en autant d'exemplaires. boolean retirer(java.lang.object obj) Retire un exemplaire de l'objet specifié de ce conteneur si cet objet y est present. int retirer(java.lang.object obj, int ncopies) Retire ncopies exemplaires de l'objet specifié de ce conteneur si cet objet y est present. java.lang.string tostring() Renvoie une représentation succincte de ce ArrayListConteneur sous forme de chaîne de caractères. Constructor Detail ArrayListConteneur public ArrayListConteneur() void vider() Retire de ce conteneur tous les objets qu'il contient. Initialise un ArrayListConteneur vide. estvide(); ArrayListConteneur public ArrayListConteneur(java.util.List<? extends E> list) Initialise un ArrayListConteneur de même contenu que la liste spécifiée. La liste spécifiée et ses éléments doivent être non null et tous les éléments de la liste doivent pouvoir être ajoutés à ce conteneur (au sens de la méthode ajoutpossible). Requires: list!= null; (\forall int i; i >= 0 && i < list.size(); list.get(i)!= null); (* Tous les éléments de list peuvent être ajoutés. *) this.getnbobjets() == list.size();
(\forall int i; i >= 0 && i < list.size(); contient(list.get(i))); (\forall E elt; contient(elt); list.contains(elt)); list - La liste contenant les éléments à placer dans ce conteneur. Throws: java.lang.nullpointerexception - si la liste spécifiée est null ou contient la valeur null. java.lang.illegalargumentexception - si certaines caractéristiques d'un des éléments de la liste spécifiée empèchent son ajout (i.e. si l'objet spécifié n'est pas null et que son ajout n'est pas possible au sens de ajoutpossible). Method Detail ajoutpossible public boolean ajoutpossible(e oz) Indique si un exemplaire de l'objet spécifié peut être ajouté à ce conteneur. Renvoie false si l'objet spécifié est null. Le résultat d'un appel à cette méthode pour un même paramètre peut varier au cours du temps en fonction des caractéristiques de ce conteneur, en particulier, la valeur renvoyée peut varier en fonction des éléments présents dans ce conteneur. Il est par exemple possible qu'un appel de cette méthode pour un objet déjà présent dans ce conteneur renvoie la valeur false. Néanmoins, il est garanti que, entre deux modifications successives de ce Conteneur, plusieurs appels à cette méthode pour un même objet renvoient le même résultat. L'implémentation fournie par cette classe renvoie true si et seulement si l'objet spécifié est non null. (oz == null) ==>!\result; \result <==> ajoutpossible(oz, 1); oz - L'objet à ajouter. true si l'objet est non null et peut être ajouté ; false sinon. ajoutpossible public boolean ajoutpossible(e oz, int ncopies) Indique si ncopies exemplaires de l'objet spécifié peuvent être ajoutés à ce conteneur. Renvoie false si l'objet spécifié est null. Le nombre d'exemplaires spécifié doit être strictement positif. Il est garanti que si un appel à cette méthode renvoie true tout appel pour le même objet et un nombre d'exemplaires inférieur renvoie aussi true ; de même il est garanti que si un appel à cette méthode renvoie false tout appel pour le même objet et un nombre d'exemplaires supérieur renvoie aussi false. Le résultat d'un appel à cette méthode pour un même paramètre peut varier au cours du temps en fonction des caractéristiques de ce conteneur, en particulier, la valeur renvoyée peut varier en fonction des éléments présents dans ce conteneur. Il est par exemple possible qu'un appel de cette méthode pour un objet déjà présent dans ce conteneur renvoie la valeur false.
Néanmoins, il est garanti que, entre deux modifications successives de ce conteneur, plusieurs appels à cette méthode pour un même objet et un même nombre d'exemplaires renvoient le même résultat. L'implémentation fournie par cette classe renvoie le même résultat que ajoutpossible(e obj) quelque soit le nombre d'exemplaires spécifié. Requires: ncopies > 0; (oz == null) ==>!\result; (ncopies == 1) ==> (\result <==> ajoutpossible(oz)); \result ==> ajoutpossible(oz); oz - L'objet à ajouter. ncopies - Le nombre d'exemplaires de l'objet à ajouter. true si l'objet est non null et que ncopies de l'objet peuvent être ajoutés ; false sinon. Throws: java.lang.illegalargumentexception - si ncopies est inférieur ou égal à 0. ajouter public void ajouter(e obj) Ajoute l'objet specifié à ce conteneur. Si l'objet est déjà présent, un exemplaire supplémentaire de cet objet y est ajouté. La presence d'un objet est testée en utilisant la methode equals. L'argument doit être non null et son ajout doit être possible au sens de la méthode ajoutpossible. Requires: ajoutpossible(obj); contient(obj); contientcombiende(obj) == \old(contientcombiende(obj)) + 1; obj - L'objet à ajouter dans ce conteneur Throws: java.lang.illegalargumentexception - si certaines caractéristiques de cet objets empèchent son ajout (i.e. si l'objet spécifié n'est pas null et que son ajout n'est pas possible au sens de ajoutpossible. java.lang.nullpointerexception - si l'objet spécifié est null.
ajouter public void ajouter(e obj, int ncopies) Ajoute ncopies exemplaires de l'objet specifié à ce conteneur. Si l'objet est déjà présent, ncopies exemplaires supplémentaires de cet objet y sont ajoutés. La presence d'un objet est testée en utilisant la methode equals. L'objet doit être non null et son ajout doit être possible au sens de la méthode ajoutpossible. ncopies doit être strictement positif. Requires: ncopies > 0; ajoutpossible(obj, ncopies); contient(obj); contientcombiende(obj) == \old(contientcombiende(obj)) + ncopies; obj - L'objet à ajouter dans ce conteneur ncopies - Le nombre d'exemplaires de l'objet à retirer de ce conteneur. Throws: java.lang.illegalargumentexception - si ncopies est inférieur ou égal à 0 ou si certaines caractéristiques de l'objet spécifié empèchent son ajout (i.e. si l'objet spécifié n'est pas null et que son ajout n'est pas possible au sens de ajoutpossible). java.lang.nullpointerexception - si l'objet spécifié est null. contient public boolean contient(java.lang.object obj) Renvoie true si le conteneur contient au moins un exemplaire de l'objet specifié. La présence d'un objet est testée en utilisant la méthode equals. Renvoie false si l'argument est null. \result <==> contientcombiende(obj) > 0; estvide() ==>!\result; obj - Objet dont on cherche à savoir s'il est present. true si ce conteneur possede au moins un exemplaire de l'objet specifié ; false sinon. contientcombiende public int contientcombiende(java.lang.object obj) Renvoie le nombre d'exemplaires de l'objet specifié presents dans ce conteneur. La presence
d'un objet est testée en utilisant la méthode equals. Renvoie 0 si l'argument est null. \result >= 0; (obj == null) ==> (\result == 0); contient(obj) <==> \result > 0;!contient(obj) <==> \result == 0; \result <= getnbobjets(); obj - Objet dont on cherche à connaitre le nombre d'exemplaires. le nombre d'exemplaires de l'objet specifié. estvide public boolean estvide() Renvoie true si ce conteneur ne contient aucun objet. \result <==> (getnbobjets() == 0); true si ce conteneur ne contient aucun objet ; false sinon. getnbobjets public int getnbobjets() Renvoie le nombre d'objets dans ce conteneur. Chaque occurence de chaque objet est comptée. \result >= 0; Le nombre d'objets dans ce conteneur. iterator public java.util.iterator<e> iterator() Renvoie un itérateur sur les éléments de ce conteneur. Specified by: iterator in interface java.lang.iterable<e> \result!= null;
Un itérateur sur les éléments de ce conteneur. memecontenu public boolean memecontenu(arraylistconteneur<?> c) Renvoie true si le ArrayListConteneur spécifié est non null et contient les mêmes objets (au sens de equals) en autant d'exemplaires. (c == null) ==>!\result; (getnbobjets()!= c.getnbobjets()) ==>!\result; c - Le conteneur à comparer avec ce conteneur. true si le conteneur spécifié contient les mêmes objets en autant d'exemplaires ; false sinon. retirer public boolean retirer(java.lang.object obj) Retire un exemplaire de l'objet specifié de ce conteneur si cet objet y est present. Renvoie true si cet objet était effectivement présent dans ce conteneur et que l'objet a pu être effectivement retiré ; renvoie false sinon. La présence d'un objet est testée en utilisant la méthode equals. Renvoie false si l'argument est null. (obj == null) ==>!\result; \old(contient(obj)) <==> \result; \old(contient(obj)) <==> (contientcombiende(obj) == \old(contientcombiende(obj)) - 1); \old(contientcombiende(obj) <= 1) <==>!contient(obj); \old(contientcombiende(obj) > 1) <==> contient(obj); obj - Objet dont un exemplaire doit être retirer de ce conteneur. true si cet objet etait effectivement present ; false sinon. retirer public int retirer(java.lang.object obj, int ncopies) Retire ncopies exemplaires de l'objet specifié de ce conteneur si cet objet y est present. Renvoie le nombre d'exemplaires de l'objet effectivement retirés. La présence d'un objet est testée en utilisant la méthode equals. Renvoie 0 si l'argument est null (et ncopies est supérieur ou égal à
0) ou si ncopies est égal à 0. ncopies doit être supérieur ou égal à 0. Requires: ncopies >= 0; obj == null ==> \result == 0; \old(contient(obj)) && ncopies > 0 <==> \result > 0; \result == (\old(contientcombiende(obj)) - contientcombiende(obj)); contientcombiende(obj) == Math.max(0, \old(contientcombiende(obj)) - ncopies); \old(contientcombiende(obj) <= ncopies) ==>!contient(obj); \old(contientcombiende(obj) > ncopies) <==> contient(obj); obj - Objet dont un exemplaire doit être retirer de ce conteneur ncopies - Nombre d'exemplaires de l'objet spécifié à retirer de ce conteneur. Le nombre d'exemplaires de l'objet effectivement retirés de ce conteneur. Throws: java.lang.illegalargumentexception - si ncopies est strictement négatif vider public void vider() Retire de ce conteneur tous les objets qu'il contient. estvide(); equals public boolean equals(java.lang.object o) Teste si l'objet spécifié est equals à ce conteneur. Pour qu'il y ait égalité entre ce conteneur et l'objet spécifié, il est nécessaire (mais non suffisant) que l'objet spécifié soit un ArrayListConteneur de même contenu (au sens de la méthode memecontenu). Selon les classes héritant de cette classe, d'autres caractéristiques de ces classes peuvent être prises en compte dans la comparaison. Deux conteneurs contenant les mêmes objets en autant d'exemplaires peuvent donc ne pas être equals. L'implémentation fournie par cette classe remplie le contrat en déclarant deux ArrayListConteneur equals si et seulement si ce sont des instances de la même sous-classe de ArrayListConteneur contenant les mêmes objets en autant d'exemplaires. En conséquence, une instance de la classe ArrayListConteneur ne peut-être equals qu'à des instances de ArrayListConteneur. Les sous-classes de ArrayListConteneur peuvent donc hériter cette méthode sans redéfinition tout en respectant à la fois le contrat défini dans la classe Object (y
compris la symétrie et la transitivité) et celui défini dans cette classe.!(o instanceof ArrayListConteneur<?>) ==>!\result; \result ==> this.memecontenu((arraylistconteneur<?>) o); this.getclass().equals(arraylistconteneur.class) ==> (\result <==> ((o!= null) && o.getclass().equals(this.getclass()) && this.memecontenu((arraylistconteneur<?>) o))); o - L'objet à comparer à ce conteneur false si l'objet spécifié n'est pas un ArrayListConteneur ou bien est un conteneur ne contenant pas les mêmes objets en autant d'exemplaires ou bien possède certaines caractéristiques différentes de celles de l'objet spécifié ; true seulement si l'objet spécifié est un ArrayListConteneur contenant les mêmes objets en autant d'exemplaires. clone public ArrayListConteneur<E> clone() Renvoie un clone de ce conteneur. L'implémentation fournie par cette classe respecte le contrat défini dans la classe Object relativement à l'implémentation de equals fournie par cette classe. Un clone de ce conteneur. hashcode public int hashcode() Renvoie un code de hashage pour ce conteneur. L'implémentation fournie par cette classe respecte le contrat défini dans la classe Object relativement à l'implémentation de equals fournie par cette classe. Un code de hashage pour ce conteneur. tostring public java.lang.string tostring() Renvoie une représentation succincte de ce ArrayListConteneur sous forme de chaîne de caractères. une représentation succincte de ce ArrayListConteneur