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

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


Exercice 1 - Jeu de cartes

En utilisant les classes 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. Ecrire un constructeur prenant en paramètre un nombre de cartes par couleur et un tableau de couleurs de cartes (Suit) et créant un jeu de carte. 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 à la place.
  6. Pourquoi le constructeur doit maintenant être privée ?
  7. Ecrire 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, ecrire 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 utlisant 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 qui ne sont pas associée à des couleurs de cartes et n'ont pas non plus de valeur.

  1. Définir une classe Wildcard qui hérite de Card et définie 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 affiche "joker" pour un joker.
    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 decide 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é pour les accès à l'extérieur pas pour les accès par les sous-classes. De plus, on remarque que l'affichage d'une carte '7 of CLUB' et d'un joker 'joker of CLUB' ont un suffix commun donc du code à partager (notez que comme on est en TD, le code est pas gros ici). Toujours est-il que l'on veut partager le code qui affiche " of " + suit pour l'implantation de Suit et pour l'implantation de Joker et en profiter pour ne pas utiliser de getter.
    Comment doit-on faire ?
    Quelle doit-être le modificateur de visibilité de la méthode que l'on ajoute ?
    Implanter la solution retenue.
  7. Expliquer pourquoi utiliser l'héritage ici n'est pas une bonne idée.

Exercice 4 - Bataille [A la maison]

Nous verons 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 valets, dames, 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. Ecrire dans la classe Deck une méthode shuffle qui renvoie un nouveau Deck dont les cartes sont mélangés.
    Attention, l'ordre des cartes du Deck existant ne doit pas être modifié.
  4. Ecrire dans la classe Deck une méthode split qui après avoir vérifier 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. Ecrire 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 carte, que les cartes sont laissés dans chaque deck.
  6. Ecrire 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ésultant du jeux de la bataille.
    Attention à vérifier que le jeux ne part pas dans une boucle infinie (rêgle du pat!).