Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente |
departement_info:personnels:pb:pa3 [2025/04/27 21:14] – [Fabrique] Brutus Philippe | departement_info:personnels:pb:pa3 [2025/06/26 16:45] (Version actuelle) – [Contrôle de connaissances] Brutus Philippe |
---|
Ce travail est à rendre par courrier électronique sous l'intitulé "TP02 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 21/02/2025 à 8h00 avec en pièce jointe le fichier "ListeChainee.java". | Ce travail est à rendre par courrier électronique sous l'intitulé "TP02 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 21/02/2025 à 8h00 avec en pièce jointe le fichier "ListeChainee.java". |
| |
{{:departement_info:personnels:pb:pa3:lst2.png?800x0&nolink}} | {{:departement_info:personnels:pb:pa3:lst2.png?700x0&nolink}} |
| |
Ce {{:departement_info:personnels:pb:pa3:lst3.zip|projet}} contient une implantation de la classe ListeChainee qui réussit tous les tests de la classe TestListeChainee. Il montre aussi que le parcours par indice d'une liste chaînée est inefficace (l'exécution de EssaiListeChainee affiche des points à chaque passage sur un élément de liste). | Ce {{:departement_info:personnels:pb:pa3:lst3.zip|projet}} contient une implantation de la classe ListeChainee qui réussit tous les tests de la classe TestListeChainee. Il montre aussi que le parcours par indice d'une liste chaînée est inefficace (l'exécution de EssaiListeChainee affiche des points à chaque passage sur un élément de liste). |
=== Mandataire === | === Mandataire === |
| |
Un mandataire (//proxy//) s'intercale entre une classe cliente C et une classe fournisseur F (objet du mandat). Au lieu d'utiliser un fournisseur de la classe F, la classe cliente donne procuration pour le faire à un objet de la classe M qui a la même API. Le mandataire relaie (ou pas) tous les appels de méthode à l'objet du mandat de la classe F mais peut effectuer d'autres traitements : mémoriser les résultats pour ne pas les redemander au fournisseur (proxy cache), bloquer certains appels (contrôle d'accès), enregistrer les sollicitations au fournisseur (journalisation)... | Un mandataire M (//proxy//) s'intercale entre une classe cliente C et une classe fournisseur F (objet du mandat). Au lieu d'utiliser un fournisseur de la classe F, la classe cliente donne procuration pour le faire à un objet de la classe M qui a la même API. Le mandataire relaie (ou pas) tous les appels de méthode à l'objet du mandat de la classe F mais peut effectuer d'autres traitements : mémoriser les résultats pour ne pas les redemander au fournisseur (proxy cache), bloquer certains appels (contrôle d'accès), enregistrer les sollicitations au fournisseur (journalisation)... |
| |
{{:departement_info:personnels:pb:pa3:mandataire.png?350x0&nolink}} | {{:departement_info:personnels:pb:pa3:mandataire.png?350x0&nolink}} |
---- | ---- |
| |
Dans la dernière version du projet Alarmes, l'enregistrement et le chargement sont définis comme des opérations en dehors des classes concernées (HeureV1, HeureV2, Alarme et ListeDAlarmes). Cela permet de les définir (et de définir d'autres opérations) sans ajouter ou modifier le code de ces classes. C'est bien le cas pour les classes HeureV1, HeureV2 et l'interface Heure ainsi que pour la classe Alarme. Mais ce n'est pas tout à fait le cas pour la classe ListeDalarmes qui dépend des classes définissant les opérations d'enregistrement et de chargement dans ces méthodes enregistreSous et charge. | Dans la dernière version du projet Alarmes, l'enregistrement et le chargement sont définis comme des opérations en dehors des classes concernées (HeureV1, HeureV2, Alarme et ListeDAlarmes). Cela permet de les définir (et de définir d'autres opérations) sans ajouter ou modifier le code de ces classes. C'est bien le cas pour les classes HeureV1, HeureV2 et l'interface Heure ainsi que pour la classe Alarme. Mais ce n'est pas tout à fait le cas pour la classe ListeDalarmes qui dépend des classes définissant les opérations d'enregistrement et de chargement dans ses méthodes enregistreSous et charge. |
| |
Pour découpler complètement la classe ListeDAlarmes des classes ChargementTexte, ChargementBinaire, EnregistrementTexte, EnregistrementXML et EnregistrementBinaire, il faudrait que l'instanciation des objets de ces classes soit réalisée en dehors de la classe ListeDAlarmes, par des méthodes de création d'objet qui crée et renvoie un objet dont la classe dépend de paramètre·s d'appel. Une classe qui crée des objets dont la classe dépend de paramètre·s est appelée une fabrique. | Pour découpler complètement la classe ListeDAlarmes des classes ChargementTexte, ChargementBinaire, EnregistrementTexte, EnregistrementXML et EnregistrementBinaire, il faudrait que l'instanciation des objets de ces classes soit réalisée en dehors de la classe ListeDAlarmes, par des méthodes de création d'objet qui créent et renvoient un objet dont la classe dépend de paramètre·s d'appel. Une classe qui crée des objets dont la classe dépend de paramètre·s est appelée une fabrique. |
| |
==== Fabrique ==== | ==== Fabrique ==== |
| |
La généralisation utilisant une interface comme couche de base (Decorable par exemple), permet de ...\\ | La fabrique est une classe de création d'objets. Elle permet d'instancier des objets dont le type est dérivé d'un type abstrait. La classe exacte de l'objet créé n'est pas connue par l'appelant. |
- ajouter des responsabilités à un objet dynamiquement au moment de l'exécution\\ | |
- ajouter des options de manière flexible, sans devoir multiplier les classes par héritage\\ | |
comme dans {{:departement_info:personnels:pb:pa3:options_cumulables.zip|cet exemple}}. | |
| |
| Dans {{:departement_info:personnels:pb:pa3:lst15.zip|cette version}} du projet Alarmes, la méthode enregistreSous n'instancie plus l'opération d'enregistrement et la méthode charge n'instancie plus l'opération de chargement. Les 2 méthodes délèguent cette instanciation à une fabrique (GestionDeFichiers) qui propose deux méthodes pour cela : operationPourEnregistrement et operationPourChargement. Chacune d'elle détermine la classe de l'objet à créer en fonction de l'argument d'appel, le nom complet de fichier, qui indique la stratégie par l'extension du nom de fichier. |
==== Exercice pour la prochaine séance ==== | ==== Exercice pour la prochaine séance ==== |
| |
Compléter {{:departement_info:personnels:pb:pa3:lst16.zip|ce projet}} pour que...\\ | Compléter {{:departement_info:personnels:pb:pa3:lst16.zip|ce projet}} pour que...\\ |
- le nom associé à chaque alarme soit lu au chargement et écrit à l'enregistrement des fichiers de version 2 ;\\ | - le nom associé à chaque alarme soit lu au chargement et écrit à l'enregistrement des fichiers de version 2 ;\\ |
- l'on puisse lire les fichiers en version 1. | - l'on puisse lire les fichiers de version 1. |
| |
| Les tests automatisés définis dans la classe de test TestEnregistrementEtChargementDeListeDAlarmes doivent tous réussir ! |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP05 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 05/05/2025 à 8h00 avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| ---- |
| |
| {{:departement_info:personnels:pb:pa3:lst17.zip|Cette version du projet}} gère les 2 versions et les 3 formats de fichiers avec une fabrique abstraite, qui n'instancie pas elle-même les objets d'enregistrement ou de chargement, mais qui fait appel à des fabriques concrètes pour le faire. |
| |
| Au chargement, la version du fichier devant d'abord être lue dans le fichier avant d'instancier le bon chargeur. Les fabriques concrètes proposent une méthode pour ouvrir le fichier afin de pouvoir y lire la version avant d'instancier le bon chargeur. |
| |
| ==== Exercice pour la séance du 5 mai ==== |
| |
| Compléter {{:departement_info:personnels:pb:pa3:lst18.zip|ce projet}} pour que...\\ |
| - le booléen associé à chaque alarme soit lu au chargement et écrit à l'enregistrement des fichiers de version 3 ;\\ |
| - l'on puisse lire les fichiers de versions 1 et 2. |
| |
| Les tests automatisés définis dans la classe de test TestEnregistrementEtChargementDeListeDAlarmes doivent tous réussir ! |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP06 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 05/05/2025 à 10h45 avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| ---- |
| |
| {{:departement_info:personnels:pb:pa3:lst19.zip|Cette version du projet}} gère les 3 versions et les 3 formats de fichiers. |
| |
| ==== Observable/Observateur==== |
| |
| Le patron de conception Observateur fournit une solution au problème de la mise à jour d'objets dits observateurs qui exploitent un objet dit observé (ou observable ou sujet) en permettant à ce dernier de notifier aux observateurs son changement d'état. |
| |
| {{:departement_info:personnels:pb:pa3:observateur.png?500x0&nolink}} |
| |
| Voici {{:departement_info:personnels:pb:pa3:observateur.zip|un exemple}} illustrant la notification à tous les titulaires d'un compte bancaire du changement de solde du compte ayant fait l'objet d'un dépôt ou d"un retrait. |
| |
| ==== Exercice pour la prochaine séance ==== |
| |
| Cette solution peut être mise en œuvre dans une application graphique qui propose plusieurs vues sur un même objet, comme dans {{:departement_info:personnels:pb:pa3:lst20.zip|cette version du projet}} qui propose différents types de vue sur les alarmes et permet d'ouvrir plusieurs fenêtres (par double-clic dans la liste) pour voir une alarme. |
| |
| Malheureusement, un changement sur une alarme affichée une ou plusieurs fois ne se répercute pas sur les vues de cette alarme. |
| |
| Compléter le projet pour que...\\ |
| - les afficheurs d'une alarme se mettent à jour lorsqu'on change le nom, change l'heure, (dés)active l'alarme affichée ;\\ |
| - l'afficheur fermé soit retiré de la liste des observateurs de l'alarme affichée ;\\ |
| - les afficheurs d'une alarme soient fermés lorsqu'on supprime l'alarme. |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP07 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 06/05/2025 à 8h00 avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| ---- |
| |
| {{:departement_info:personnels:pb:pa3:lst21.zip|Cette version du projet}} gère correctement les multiples vues d'une alarme :\\ |
| - après création d'un afficheur d'alarme, le contrôleur l'ajoute à la liste des observateurs de l'alarme (par un appel de la méthode ajouteObservateur) ;\\ |
| - après modification d'une alarme, le contrôleur notifie tous les observateurs de cette alarme (par un appel de la méthode notifieObservateurs) ;\\ |
| - à la fermeture de la fenêtre d'un afficheur d'alarme, ce dernier est retiré de la liste des observateurs de l'alarme (par un appel à la méthode retireObservateur dans l'écouteur de fenêtre) ;\\ |
| - à la suppression d'une alarme, tous ses observateurs sont supprimés (dans le destructeur de la classe Alarme) et cette destruction entraîne la fermetures des fenêtres. |
| |
| ==== Java et XML ==== |
| |
| Il existe 2 paquetages java pour manipuler des documents au format {{:departement_info:personnels:pb:pa3:xml.pdf|XML}} :\\ |
| - SAX : Simple API for XML ;\\ |
| - DOM : Document Object Model. |
| |
| On utilise {{:departement_info:personnels:pb:pa3:sax.pdf|SAX}} pour extraire de l'information d'un document en définissant des déclencheurs sur certaines balises. Cela permet de lire et traiter des flux XML. |
| |
| Avec {{:departement_info:personnels:pb:pa3:dom.pdf|DOM}}, on charge le document en créant une représentation en mémoire sous forme d'arbre. Cela permet de manipuler et reconvertir le document. |
| |
| Voici {{:departement_info:personnels:pb:pa3:java_XML.zip|quelques exemples d'utilisation}} de SAX et [[https://fr.wikipedia.org/wiki/JDOM|jDOM]]. |
| |
| ---- |
| |
| {{:departement_info:personnels:pb:pa3:lst22.zip|Cette version du projet}} tente d'ouvrir un fichier de préférences au format XML.\\ |
| En cas d'échec (fichier inexistant par exemple), elle crée un arbre des préférences par défaut puis l'enregistre.\\ |
| |
| ==== Exercice pour la prochaine séance ==== |
| |
| Compléter le projet pour que les préférences lues dans le fichier alarmes.xml soient prises en compte. |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP08 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 02/06/2025 à 8h00 avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| ---- |
| |
| {{:departement_info:personnels:pb:pa3:lst23.zip|Cette version du projet}} tente d'ouvrir un fichier de préférences au format XML.\\ |
| En cas d'échec (fichier inexistant par exemple), elle crée un arbre des préférences par défaut puis l'enregistre.\\ |
| En cas de succès, elle prend en compte les 2 préférences lues dans le fichier (couleur d'affichage des alarmes actives et son émis quand il est l'heure d'une alarme active). |
| |
| ==== Commande ==== |
| |
| Il s'agit de transformer une action à effectuer en un objet autonome (réification) qui contient tous les détails de cette action. Cette transformation permet de paramétrer des méthodes avec différentes actions, planifier leur exécution, ou les mettre dans une file d’attente. |
| |
| Cela permet de séparer complètement le code initiateur de l'action, du code de l'action elle-même. |
| |
| On utilise beaucoup cette solution dans les interfaces graphiques où, par exemple, un item de menu et un bouton sont connectés à la même commande. |
| |
| {{:departement_info:personnels:pb:pa3:commande.png?380x0&nolink}} |
| |
| ==== Exercice ==== |
| |
| Compléter {{:departement_info:personnels:pb:pa3:lst24.zip|cette version du projet}} pour que l'item "Nouvelle" du menu "Alarme" et le bouton "Nouvelle alarme" réalisent la même action en utilisant cette solution. |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP09 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| {{:departement_info:personnels:pb:pa3:lst25.zip|Cette version du projet}} implante une commande pour les deux invocateurs. |
| |
| ==== Memento ==== |
| |
| Il s'agit de conserver l'état d'un objet pour le restaurer par la suite si nécessaire... C'est un gardien qui se charge de conserver l'état à restaurer. Si plusieurs modifications sont effectuées, le gardien peut conserver les différents états pour en rétablir un parmi ceux qu'il conserve. |
| |
| Dans les interfaces graphiques, on trouve cette solution dans le concept de presse-papiers. |
| |
| {{:departement_info:personnels:pb:pa3:memento.png?550x0&nolink}} |
| |
| ==== Exercice ==== |
| |
| Compléter {{:departement_info:personnels:pb:pa3:lst26.zip|cette version du projet}} pour que l'item "Annuler" du menu "Edition" soit opérationnel en permettant de revenir en arrière plusieurs fois si possible. |
| |
| Ce travail est à rendre par courrier électronique sous l'intitulé "TP10 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). |
| |
| {{:departement_info:personnels:pb:pa3:lst27.zip|Cette version du projet}} implante un état dans la classe Alarme et définit une variable d'instance de type Gardien dans la classe Controleur pour stocker des Mémentos à l'ajout, la modification ou la suppression d'une alarme, ce qui permet de définir une méthode "annule" pour restaurer la situation précédente de la liste d'alarmes. |
| |
| ==== Récapitulons ==== |
| |
| Les arrangements caractéristiques vus précédemment sont reconnus comme bonnes pratiques en réponse à des problèmes récurrents. Ils décrivent les grandes lignes d'une solution. On peut les modifier ou les adapter en fonction des besoins. On les appelle {{:departement_info:personnels:pb:pa3:patrons.pdf|patrons de conception}}. |
| |
| {{:departement_info:personnels:pb:pa3:carte_des_patrons.pdf|Carte des patrons de conception}}. |
| |
| ==== Introspection (réflexivité) ==== |
| |
| L'introspection pour un langage de programmation est la capacité à traiter non seulement du domaine dans lequel on écrit un programme mais aussi à traiter du programme lui-même. Elle confère aux langages qui en sont capables des possibilités inédites. |
| |
| L'introspection est rendue possible par les méthodes proposées dans les classes Object, Class, Field et Method du paquetage java.lang.reflect, dont les principales sont présentées dans {{:departement_info:personnels:pb:pa3:introspection.pdf|ce document}}. |
| |
| {{:departement_info:personnels:pb:pa3:introspection.zip|exemple d'introspection}} |
| |
| ==== Injection de dépendances ==== |
| |
| L'injection de dépendances applique le principe d'inversion de contrôle pour créer dynamiquement (injecter) les dépendances entre les différents objets en s'appuyant sur une description (fichier de configuration ou métadonnées) ou par programme. |
| |
| Elle est utile pour remplacer une classe par une autre, notamment pour la réalisation de tests unitaires avec des objets factices ([[http://easymock.org/|easymock]], [[https://site.mockito.org/|mockito]]). |
| |
| L'{{:departement_info:personnels:pb:pa3:injection_de_dépendances.pdf|injection de dépendances}} est expliquée dans l'[[https://martinfowler.com/articles/injection.html|article de Martin Fowler]] qui évoque les frameworks permettant d'en faire (Spring par exemple). |
| |
| |
| ==== Contrôle de connaissances ==== |
| |
Ce travail est à rendre par courrier électronique sous l'intitulé "TP05 NFP121" à l'adresse "philippe.brutus (à) caensup.fr" pour le 25/04/2025 à 8h00 avec en pièce jointe l'archive contenant les seuls fichiers modifiés ou ajoutés (dans leurs paquets respectifs). | L'Unité d'Enseignement est évaluée par un examen écrit noté sur 20 auquel s'ajoute un bonus pouvant aller jusqu'à 3 points pour les exercices rendus. |
| |
==== Pour partager le travail en cours ==== | {{:departement_info:personnels:pb:pa3:sujet1_2021.pdf|le sujet de l'examen de première session de 2021 à Caen}} |
| |
{{:departement_info:personnels:pb:pa3:partage.zip|partage}} | public class TacheElementaire extends Tâche{ |
| private int coût; |
| public TacheElementaire(String nom, int coût) throws RuntimeException{ |
| super(nom); |
| if (coût < 0) |
| throw new RuntimeException("Tentative de création d'une tâche avec un coût (" + coût + ") négatif !"); |
| this.coût = coût; |
| } |
| public int coût() { |
| return coût; |
| } |
| } |
| |
| import java.util.List; |
| import java.util.LinkedList; |
| |
| public class TâcheComplexe |
| extends Tâche |
| //implements TâcheI |
| { |
| private List<Tâche> contenu; |
| public TâcheComplexe(String nom) { |
| super(nom); |
| contenu = new LinkedList<Tâche>(); |
| } |
| public void ajoute(Tâche t) { |
| contenu.add(t); |
| } |
| public int coût() { |
| int total = 0; |
| for(Tâche t : contenu) { |
| total += t.coût(); |
| } |
| return total; |
| } |
| public int taille() { |
| return contenu.size(); |
| } |
| public void retire(int index) { |
| contenu.remove(index); |
| } |
| } |
| |
| //=============================================== |
| |
| interface Image { |
| public void displayImage(); |
| } |
| class RealImage implements Image { |
| //... |
| } |
| |
| class ProxyImage implements Image { |
| private RealImage image; |
| private String nomFichier; |
| public ProxyImage(String filename) { |
| image = null; |
| nomFichier = filename; |
| } |
| public void displayImage() { |
| if (image == null) |
| image = new RealImage(nomFichier); |
| image.displayImage(); |
| } |
| } |
| |
| public class LesImages { |
| private List<Image>contenu; |
| public LesImages() { |
| contenu = new LinkedList<ProxyImage>(); |
| } |
| public void ajoute(String filename) { |
| contenu.add(new ProxyImage(filename); |
| } |
| public void displayImage(int index) { |
| contenu.get(index).displayImage(); |
| } |
| public int taille() { |
| return contenu.size(); |
| } |
| } |
| |
| LesImages images = new LesImages(); |
| images.ajoute("fruit"); |
| images.displayImage(0); |
| |
| |
| {{:departement_info:personnels:pb:pa3:sujet1_2025.pdf|Le sujet}} et {{:departement_info:personnels:pb:pa3:corrigé1_2025.pdf|un corrigé}} de l'examen de première session de 2025 à Caen. |
| |
| |