Activité Gérons nos items, principe de substitution de Liskov et principe de ségrégation des interfaces

Objectifs

À la fin de ce travail, vous devez :

  1. Connaître la relation « est un »
  2. Connaître la notion d’interface
  3. Connaître la différence entre type et classe
  4. Connaître les quatre premiers principes SOLID (SRP, OCP, LSP, ISP)

Consigne

Pour ce travail on vous demande de prendre connaissance de la situation et de réaliser les tâches proposées. Si vous ne parvenez pas à terminer le travail en classe, il vous appartient de prendre sur votre temps pour l’achever.

Le code des tests unitaires doit être utilisé tel quel et ne doit pas être modifié. Le code des classes doit être conforme à la spécification fournie sous forme de tests unitaires et de diagramme UML.

Le travail est individuel. Vous pouvez communiquer en respectant le code d’honneur.

Résultat attendu

Un projet Maven

Ressources

Logiciel :

  • Machine virtuelle de développement
  • Visual Studio Code

Documents :

Situation

Vous êtes développeur dans un projet de logiciel de gestion de bibliothèque. Après la réunion avec le client, vous avez modifié les classes du système de gestion de bibliothèque en utilisant la relation « est un » entre les classes Book, Documentary et Periodical et la classe LibraryItem.

Lors d’une revue de code avec un collègue, celui-ci relève que vous utilisez le sous-typage (avec le mot clé implements) à bon escient, car vous respectez le principe de substitution de Liskov (Liskov substitution principle, LSP, le L de SOLID). Il remarque, en effet, qu’il est possible d’utiliser une expression de type Book, Documentary ou Periodical n’importe où une expression de type LibraryItem est attendue et que cela est conforme au LSP qui stipule précisément qu’un type S est un sous-type d’un super-type T s’il est possible de substituer n’importe quelle expression de type T par une expression de type S. À ce propos, il précise que lors d’un code review, il vérifie toujours que les sous-types sont bien des sous-types selon la définition de Liskov, car ni Java ni aucun autre langage ne peut garantir le respect du LSP.

Votre collègue relève également qu’en utilisant le super-type LibraryItem, vous respectez le principe ouvert-fermé (open-closed principle, OCP, le O de SOLID) qui stipule qu’une classe doit être ouverte pour l’extension et fermée pour la modification. Or, vous dit-il, grâce à cette interface, il est possible d’ajouter de nouvelles sortes d’items dans la bibliothèque sans avoir à modifier ni les classes qui correspondent aux sortes d’items existantes (Book, Documentary et Periodical) ni la classe Copy.

Il s’attarde ensuite sur les classes Loan et LoanManager et comme vous le voyez froncer un peu les sourcils vous lui demandez ce qui le dérange. Il vous répond que puisque vous connaissez maintenant la notion d’interface, on pourrait en faire usage pour améliorer le design de l’application en appliquant un autre principe SOLID : le principe de ségrégation des interfaces (interface segregation principle, ISP, le I de SOLID). Il vous explique que ce principe stipule qu’un client ne devrait pas dépendre de méthodes qu’il n’utilise pas. Or, vous fait-il remarquer, la classe Loan expose des accesseurs sans doute utiles pour les tests, mais dont la classe LoanManager n’a pas besoin. Il vous propose donc de renommer la classe Loan en LoanImpl puis de créer une interface Loan conformément au diagramme UML de la figure 1 et enfin de modifier l’instanciation des objets de type Loan classe LoanManager ; Loan étant désormais une interface, l’instanciation (opérateur new) doit se faire en utilisant le nom de la classe qui l’implémente (LoanImpl).

Fig. 2 – Système de gestion de bibliothèque
Fig. 1 – Sous-système de gestion des emprunt

Il poursuit en vous faisant remarquer que les classes Author, Writer et Director sont identiques et représentent toutes des personnes ou, plus précisément, des noms de personnes. Il vous propose donc de ne faire qu’une seule classe PersonName. Vous objectez qu’on ne sait alors plus qui est auteur, scénariste ou réalisateur. Il vous rétorque que le rôle d’une personne n’est pas une propriété intrinsèque de cette personne, une même personne peut avoir différent rôle selon le contexte dans lequel elle se trouve. C’est la relation entre le film et la personne qui détermine si la personne en est le scénariste ou le réalisateur. De plus, ajoute-t-il, il est possible qu’une personne soit tout à la fois scénariste et réalisateur. Pour finir, il vous suggère d’utiliser pour la classe PersonName le même principe que pour Loan, c’est-à-dire définir une interface PersonName et une classe PersonNameImpl qui implémente cette interface.

Pour finir, il remarque que les méthodes de la classe LoanManager prennent en paramètre un objet de type Copy mais qu’il n’utilise de cet objet que l’attribut Id et rien d’autre. Cette fois, vous voyez où il veut en venir : cela va à l’encontre du principe de ségrégation des interfaces. Mais créer une interface avec un seul attribut vous semble exagéré. Lorsque vous lui faites part de votre réserve, il vous la concède et vous propose alors de passer en paramètre l’identificateur sous la forme d’une chaîne de caractère. L’avantage de ce nouveau design est que l’on voit apparaître un sous-système d’emprunt complètement découplé du reste. Vous révisez donc le modèle de l’application pour tenir compte de ces observations et vous obtenez les diagrammes des figures 1 et 2.

Fig. 3 – Sous-système de gestion des items
Fig. 2 – Sous-système de gestion des items

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-items-lsp-isp.git --single-branch

Lorsque le système vous y invite, saisissez votre nom et votre mot de passe I-FR.

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

À vous de jouer !

Tâches

  1. Modifiez le projet pour qu’il corresponde aux diagrammes UML des figures 2 et 3.

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