Activité : Gérons nos livres

Objectifs

À la fin de ce travail, vous devez :

  1. Être capable de lire un diagramme de classe en UML.
  2. Être capable d’écrire le squelette d’une classe en Java sans aide.
  3. Être capable d’utiliser les tests unitaires comme d’une spécification pour implémenter les méthodes.
  4. Être capable d’utiliser les tests unitaires pour valider le bon fonctionnement de votre code.
  5. Connaître la classe ArrayList<T> et ses principales méthodes.
  6. Être capable d’ajouter et récupérer un élément dans une liste de type ArrayList<T>.
  7. Être capable d’itérer les éléments d’une liste de type ArryList<T> avec une boucle définie.
  8. Être capable d’utiliser des commentaires JavaDoc pour documenter les classes.

Consigne

Le but de cette activité est d’être capable de réaliser des classes en Java à partir d’un diagramme de classes UML et de tests unitaires qui tiennent lieu de spécification.

On vous demande de prendre connaissance de l’ensemble du document avant de réaliser les tâches décrites ci-après. Si vous ne parvenez pas à terminer le travail en classe, il vous appartient de prendre sur votre temps pour l’achever.

Les classes Book, Author et Copy doivent être conformes au diagramme UML; elles ne doivent pas contenir de méthodes publiques qui ne figurent pas dans le diagramme. S’il y a une différence entre les tests unitaires et le diagramme de classe, les tests unitaires font foi.

Le code des tests unitaires doit être utilisé tel quel et ne doit pas être modifié.

Le travail est individuel. Si vous rencontrez des difficultés que vous ne parvenez pas à surmonter seul, vous pouvez communiquer avec vos camarades en respectant le code d’honneur, ou demander de l’aide à votre enseignant. En dehors des heures de cours, il est également possible de poser des questions par courriel ou à l’aide de la messagerie instantanée de Teams.

Lorsque vous avez terminé l’activité, assurez-vous d’avoir atteint tous les objectifs.

Résultat attendu

Un projet Maven contenant les classes suivantes :

  • Book, Author, Copy et StringUtils
  • BookTest, AuthorTest et CopyTest

Ressources

Logiciel :

  • Maven
  • Visual Studio Code

Documents :

Situation

Vous participez au développement d’un logiciel de gestion de bibliothèque et vous êtes chargé de réaliser en Java les classes décrites par le diagramme UML de la figure 1. En plus du diagramme, vous recevez les classes BookTest, AuthorTest, CopyTest et StringUtilsTest qui contiennent des tests unitaires. Votre supérieur vous informe que dans ce diagramme de classe, la classe Copy représente les exemplaires physiques des livres de la bibliothèque et que les tests unitaires tiennent lieu de spécification pour les classes que vous devez réaliser.

Fig. 1 – Diagramme de classe à réaliser
Fig. 1 – Diagramme de classes UML

Mise en route

Lancez la machine virtuelle de développement avec Vagrant. Lancez Visual Studio Code, connectez-vous à la machine virtuelle et ouvrez la fenêtre de terminal intégré.

Rendez-vous dans le répertoire de projets (~/projects) et lancez la commande suivante :

1
git clone https://gitlab.epai-ict.ch/m226/gerons-nos-livres.git --single-branch

Déplacez-vous dans le répertoire gerons-nos-livres et lancer la commande code -r . pour ouvrir le projet.

À vous de jouer !

Tâche

Réaliser les squelettes des classes

La première étape est d’éliminer les erreurs de syntaxe dans les tests unitaires. Pour cela, la méthode que nous vous recommandons est d’écrire le squelette de chacune des classes.

Écrire le squelette d’une classe consiste à n’écrire que le code strictement nécessaire pour cette classe. Le code ci-dessous est le squelette de la classe Author. On peut voir qu’elle ne contient que les méthodes publiques et que celles-ci sont toutes implémentées de la même manière. L’instruction throw new UnsupportedOperationException(); indique que la méthode n’est pas encore implémentée et assure l’échec des tests unitaires correspondants.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package ch.epai.ict.m226.gerons_nos_livres;

/**
 * Représente le nom d'un auteur d'un livre du catalogue.
 */
public class Author {

    /**
     * Constructeur
     *
     * @param id        l'identifiant de l'auteur
     * @param lastName  le nom de l'auteur
     */
    public Author(long id, String lastName) {
        throw new UnsupportedOperationException();
    }

    /**
     * Constructeur
     * 
     * @param id        l'identifiant de l'auteur
     * @param lastName  le nom de l'auteur
     * @param firstName le prénom de l'auteur
     */
    public Author(long id, String lastName, String firstName) {
        throw new UnsupportedOperationException();
    }

    /**
     * Accesseur pour l'identifiant de l'auteur.
     *
     * @return l'identifiant
     */
    public long getId() {
        throw new UnsupportedOperationException();
    }

    /**
     * Accesseur pour le nom de l'auteur.
     *
     * @return le nom
     */
    public String getLastName() {
        throw new UnsupportedOperationException();
    }

    /**
     * Accesseur pour le prénom de l'auteur.
     *
     * @return le prénom
     */
    public String getFirstName() {
        throw new UnsupportedOperationException();
    }

    /**
     * Renvoie une chaîne qui contient l'initiale du prénom suivit
     * du nom de l'auteur.
     *
     * @return le nom complet
     */
    public String getFullName() {
        throw new UnsupportedOperationException();
    }
}

Réalisez le squelette des trois autres classes. Lorsque vous n’avez plus d’erreurs de syntaxe, lancez les tests unitaires et assurez-vous que tous ont échoué.

Implémenter la classe StringUtils

La classe StringUtils est une classe utilitaire, c’est-à-dire une classe qui ne contient que des méthodes statiques. Pour l’instant, elle ne contient qu’une méthode qui renvoie la chaîne passée en paramètre ou une chaîne vide (empty string) si la valeur du paramètre est null.

Comme la classe n’a pas de variables membres et que toutes ses méthodes sont statiques, son instanciation n’a pas de sens. Pour éviter de l’instancier par erreur, on ajoute à la classe un constructeur privé, ce qui rend l’instanciation impossible.

Implémenter les classes Author et Book

Implémentez les méthodes des classes Author, Book (dans cet ordre) et lancez les tests unitaires pour valider votre travail.

Rappels :

  • Les variables membres sont déclarées tout en haut de la classe, à la ligne qui suit l’accolade ouvrante.

  • Toutes les variables membres doiven être private en vertu du principe de masquage de l’information (information hiding).

  • Pour implémenter les constructeurs, commencez par celui qui a le plus de paramètres et utilisez des appels à ce constructeur pour implémenter les autres (this(...)).

  • Le rôle d’un constructeur est d’affecter une valeur à chaque variable membre.

Ne poursuivez que lorsque tous les tests des classes AuthorTest et BookTest passent avec succès.

Implémenter la classe Copy

Si vous avez effectué toutes les tâches précédentes, vous pouvez implémenter les méthodes des classes Copy. Utilisez les commentaires des tests unitaires pour déterminer ce qu’il faut faire.

Pour réaliser cette tâche, vous avez besoin de la classe LocalDate qui permet de représenter une date. Cette classe définie, entre autres, une méthode plusDays qui permet de créer une nouvelle date en ajoutant un certain nombre de jours à la date, ainsi que deux méthodes isAfter et isBefore qui permettent de tester si la date se situe après ou avant une autre date passée en paramètre. Vous avez également besoin de l’instruction throw new RuntimeException("un message"); pour jeter une exception lorsqu’un test unitaire le demande. Remplacez la chaîne "un message" par un message qui indique pourquoi l’exception a été jetée.

Demandez de l’aide en cas de besoin, mais essayez d’abord par vous-même et respectez toujours le code d’honneur !