:: Enseignements :: Licence :: L3 :: 2013-2014 :: Programmation Objet avec Java ::
[LOGO]

Mutabilité, constructeur, factory method, héritage, varargs


Exercice 1 - Jeu de cartes

En utilisant une classe Card qui représente une carte et une classe Suit qui répresente une couleur (pique, trèfle, coeur ou carreau), on souhaite écrire une classe Deck (dans le package fr.umlv.card) représentant un jeu de cartes. Cette classe utilisera la classe java.util.ArrayList pour stocker les cartes.


  1. Créer une classe Main et afficher dans le main de celle-ci la valeur de SPADE.
    Rappeler quelle est la différence principale entre un enum en C et un enum en Java ?
  2. Créer une classe Deck. Écrire un constructeur prenant en paramètre un nombre de cartes par couleur et un tableau de couleurs de carte (Suit) et créant un jeu de cartes. Pour deux cartes par couleur et avec les couleurs CLUB et HEART, le jeu doit contenir quatre cartes (1 CLUB, 2 CLUB, 1 HEART, 2 HEART) dans cet ordre.
    Pour tester, vous écrirez aussi la fonction d'affichage habituelle.
  3. Modifier le constructeur pour que l'on puisse l'appeler en séparant les couleurs par des virgules. Utiliser la notation un varargs (ou ellipsis) pour cela.
    Deck deck = new Deck(2, Suit.CLUB, Suit.HEART);
  4. Utiliser un import static pour pouvoir désigner CLUB et HEART sans les préfixés par Suit ce qui permettra d'écrire le code suivant:
    Deck deck = new Deck(2, CLUB, HEART);
  5. Expliquer pourquoi utiliser un constructeur pour cela n'est pas une bonne idée.
    Modifier le code pour utiliser une factory method createDeck à la place.
  6. Pourquoi le constructeur doit-il maintenant être privé ?
  7. Écrire une méthode equals qui compare deux Decks (l'ordre des cartes est important).
    Pourquoi doit-on modifier la classe Card ?

Exercice 2 - Mutabilité

  1. En réutilisant la classe Deck, écrire une méthode getCardList qui renvoie une liste de carte.
    Pourquoi le type de retour de la méthode ne doit pas être ArrayList ?
  2. Le code suivant montre que votre méthode getCardList est mal codée
         Deck deck = ...
         deck.getCardList().remove(0);
        
    Pourquoi ?
    Résoudre le problème en utilisant une copie défensive.
  3. Quelle est le problème de la copie défensive sur une collection ?
    Pourquoi est-il plus efficace d'utiliser la méthode java.util.Collections.unmodifiableList() ?
    Modifier votre code en conséquence.

Exercice 3 - Joker

On souhaite ajouter des cartes joker (wilcard dans la langue de Shakespeare) qui ne sont pas associées à des couleurs de carte et n'ont pas non plus de valeur.

  1. Définir une classe Wildcard qui hérite de Card et définit un joker.
    Expliquer pourquoi le compilateur vous oblige à écrire un constructeur. Où si vous préférez, pourquoi le constructeur par défaut fourni par le compilateur ne fonctionne pas ?
  2. Expliquer pourquoi il est possible d'ajouter un joker (de type Wildcard) dans un deck.
  3. Ajouter dans Deck une méthode permettant de créer un deck en indiquant en plus des paramètres de nombre de cartes et de couleurs, un nombre de jokers.
  4. Vérifier que l'affichage d'un deck est bien "joker" pour un joker. Si ce n'est pas la cas, quelle méthode doit-on aussi ré-écrire ?
    Que doit-on faire lorsque l'on hérite d'une classe en plus d'écrire le constructeur ?
  5. Finalement, on décide que les jokers doivent avoir une couleur, l'affichage d'un joker ne sera donc plus simplement "joker" mais "joker of SPADE" par exemple.
    Pour que cela marche, pourquoi doit-on ajouter un getter à la classe Card?
  6. En fait, utiliser un getter pour cela n'est pas très 'objet', les getter doivent être utilisés pour les accès à l'extérieur, non pas pour les accès par les sous-classes.
    Comment peut-on modifier le code pour se passer de ce getter?
    Note: si vous voulez mettre un champs public ou protected, ce n'est pas la solution !
    Indice: on remarque que le code qui affiche " of " + suit est commun aux 2 classes...
    Quel doit-être le modificateur de visibilité de la méthode que l'on ajoute ?
    Implanter la solution retenue.
  7. N'oubliez pas de modifier la méthode permettant de créer un deck avec jocker (on choisit le nombre de jocker/couleur, le nombre de carte/couleur et les couleurs).
  8. Quelles sont les différences entre les classes Card et Wildcard. Rappeler dans quel cas il faut utiliser l'héritage et dans quel cas il ne faut pas utiliser l'héritage.
    Comment les jokers devraient-ils être implantés si on n'utilisait pas l'héritage ?

Exercice 4 - Bataille [A la maison]

Nous verrons dans le TD suivant ce qu'il fallait utiliser au lieu de l'héritage.
En attendant, je vous propose de jouer à la bataille, avec des jokers bien sûr.

  1. Modifier la classe Card pour afficher valet, dame, roi, as (en anglais SVP) à la place de leur valeur numérique.
    Pitié pour le processeur, éviter les if ... else imbriqués.
  2. Dans l'exemple suivant, on mélange une liste et le tableau se retrouve mélangé
           String[] array = new String[] { "baz", "foo", "bar" };
           List<String> list = Arrays.asList(array);
           Collections.shuffle(list);
           System.out.println(Arrays.toString(array));
         
    Expliquez ce mystère.
  3. Écrire dans la classe Deck une méthode createShuffleDeck qui renvoie un nouveau Deck dont les cartes sont mélangées.
    Attention, l'ordre des cartes du Deck existant ne doit pas être modifié.
  4. Écrire dans la classe Deck une méthode split qui après avoir vérifié que le deck contenait un nombre pair de cartes, créé deux nouveaux Deck ayant chacun la moitié des cartes.
    Attention, l'ordre des cartes du Deck existant ne doit pas être modifié.
  5. Écrire une méthode fight qui prend une liste de decks et renvoie une liste de nouveaux decks en ayant appliqué entre eux un tour des règles de la bataille. On considérera qu'en cas de bataille alors qu'il n'y a plus assez de cartes, les cartes sont laissées dans chaque deck.
  6. Écrire un main de test, qui génère deux decks à partir d'un jeu de 32 cartes (donc pas de joker :), affiche ceux ci, puis affiche tour par tour les decks résultants du jeux de la bataille.
    Attention: vérifier que le jeu ne part pas dans une boucle infinie (règle du pat!).