Activité Introduction aux patrons de conception : patrons de création d'objets (partie 2/3)

Objectifs

À la fin de ce travail, vous devez :

  1. Être capable d’expliquer l’utilité des patrons de conception de création (creational design pattern)
  2. Être capable de décrire et de distinguer les patrons de conception de création d’objets :
    • « Static Factory Method »
    • « Abstract Factory »
    • « Builder »

En plus des objectifs principaux ci-dessus, vous devez :

  1. Connaître le principe de masquage de l’information (information hidding).
  2. Connaître les modificateurs public, private et protected pour les membres (attributs et méthodes) d’une classe.
  3. Être capable d’expliquer pourquoi un constructeur n’est jamais virtuel.

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 travail est individuel. Vous pouvez communiquer en respectant le code d’honneur.

Résultat attendu

  • Un projet Maven contenant les classes décrites
  • Un petit document où vous aurez décrit ce que vous avez fait et les difficultés que vous aurez rencontrées.

Ressources

Logiciel :

  • Machine virtuelle de développement
  • Visual Studio Code

Documents :

Situation

Dans le cadre d’un projet de gestion de contacts, vous avez réalisé un « Data Mapper » qui présente une collection d’objets de type Person qui peut être chargée depuis différents formats de fichier.

Vous présentez votre travail au responsable du projet pour une revue de code. Pour documenter votre travail, vous avez réalisé les diagrammes des figures 1 et 2. Le premier est un diagramme de classes qui représente les relations et les dépendances entre les classes. Le second est un diagramme de séquence dont le but est de fournir une représentation temporelle des interactions (appels de méthodes) entre les objets (instances).

Fig. 1 – Diagramme de classes (vue statique): représentation des relations et les dépendance entre des classes
Fig. 1 – Diagramme de classes (vue statique) :
représentation des relations et des dépendances entre des classes
Fig. 2 – Diagramme de séquence (vue dynamique): représentation temporelle des interactions entre des objets (instances)
Fig. 2 – Diagramme de séquence (vue dynamique) :
représentation temporelle des interactions entre des objets (instances)

Le responsable du projet est plutôt satisfait de votre travail. En effet, il constate plusieurs choses intéressantes :

  1. Vous avez utilisé le patron de conception « Static Factory Method » proposé par Joshua Bloch pour instancier l’objet « factory » (DataMapperFactory.newInstance);
  2. Ensemble, l’interface DataMapperFactory, la classe DataMapperFactoryImpl et les sous-types de PersonDataMapper forment une instance (légèrement simplifiée) du patron de conception « Abstract Factory », également un patron de conception du GoF.
  3. Grâce à l’utilisation de ces patrons de conception de création (creational design patterns), le client de la bibliothèque (la classe App) dépend uniquement de classes abstraites (interfaces java) et nom de classes concrètes; le principe d’inversion des dépendances (dependency inversion principle) est de ce point de vue bien respecté.

Il voit cependant également quelques possibilités d’amélioration. Il remarque notamment que l’implémentation de la classe PersonDataMapperCsv et PersonDataMapperXml ne diffèrent que par l’implémentation de la méthode readFile. Cela correspond à un « anti-pattern » connu sous le nom de « programmation copier/coller ». Avec un langage orienté-objet comme Java, on peut utiliser l’héritage pour éviter ce problème. Il vous propose donc le diagramme de la figure 3.

Fig. 3 – Utilisation de l'héritage pour éviter le copier/coller dans les implémentations de PersonDataMapper.
Fig. 3 – Utilisation de l'héritage pour éviter le copier/coller dans les implémentations de PersonDataMapper.

Il ajoute la remarque suivante : autant que possible, on respecte le principe de dissimulation d’information entre la classe de base et les classes dérivées. Cela signifie que les variables membres d’une classe de base doivent également être déclarées comme étant privées. L’initialisation des variables membres de la classe de base est la responsabilité du constructeur de la classe de base et non celle du constructeur de la classe dérivée. Un constructeur n’est donc jamais virtuel et ne peut pas être surécrit (overloaded). De plus, le constructeur d’une classe dérivée doit invoquer le constructeur de sa classe de base à l’aide du mot clé super avant d’initialiser ses propre variables membres. Si la classe de base est abstraite, elle ne peut pas avoir de constructeur public. Dans ce cas, on utilise le modificateur protected pour le rendre visible par les classes dérivées.

Mise en route

Faites une copie du projet de l’activité précédente.

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), puis dans le répertoire de votre nouveau projet et lancer la commande code -r . pour l’ouvrir.

Tâches

  1. Modifiez votre code de telle sorte qu’il corresponde au diagramme de la figure 3.
  2. Expliquez ce qu’est une méthode virtuelle, une méthode virtuelle pure et une méthode non-virtuelle.
  3. En Java, comment indique-t-on qu’une méthode est (a) virtuelle (b) virtuelle pur (c) non-virtuelle ?
  4. Expliquez avec vos propres mots la manière dont on utilise le mot clé super dans le constructeur de la classe dérivée et la raison pour laquelle on procède ainsi.
  5. Un constructeur peut-il être virtuel ? Justifiez votre réponse.
  6. Expliquez la raison pour laquelle il n’est pas recommandé d’utiliser le mot clé protected pour les variables membres. Quel principe cela violerait-il ?
  7. Dans notre cas, par quel truchement la classe dérivée a-t-elle accès à la variable membre persons pour y ajouter les personnes qui se trouvent dans le fichier ?
  8. Proposez une autre solution pour permettre à la classe dérivée d’ajouter des personnes dans la liste persons sans modifier sa visibilité (elle doit rester privée).
  9. Réaliser deux tests unitaires pour vérifier le bon fonctionnement de la classe PersonDataMapperXml et celui de la classe PersonDataMapperCsv. Vous pouvez utiliser pour cela le fichier XML et le fichier CSV qui vous ont été fournis avec le projet.
  10. Observez les classes PersonDataMapperFileBase, PersonDataMapperCsv et PersonDataMapperXml. Ces classes respectent-elles les principes SOLID ? Le cas échéant, indiquez quels principes ne sont pas respectés et justifiez votre réponse.

Attention : Documentez-vous et vérifiez, éventuellement à l’aide d’expériences, si le comportement correspond bien vos explications !