Principes et patrons de conception OO
Principes et patrons de conception OO
Christine Solnon
2019 - 2020
1/57 .
Plan du cours
1 Introduction
2/57 .
Quelques principes de conception orientée objet
3/57 .
Patrons de conception (Design patterns)
4/57 .
23 patrons du Gang of Four (GoF)
[E. Gamma, R. Helm, R. Johnson, J. Vlissides]
1 Introduction
6/57 .
L’application PlaCo (rappel)
Une scierie, équipée d’une machine de découpe au laser, veut un système
pour dessiner les plans à transmettre à la machine.
L’application doit permettre d’ajouter, supprimer et déplacer des formes
sur un plan, de sauvegarder et charger des plans, et de transmettre un
plan au système de découpe.
Chaque plan a une hauteur et une largeur.
Les formes sur un plan sont des rectangles et des cercles :
un rectangle a une largeur et une hauteur, et sa position est définie
par les coordonnées de son coin supérieur gauche ;
un cercle a un rayon, et sa position est définie par les coordonnées
de son centre.
Les coordonnées et les longueurs sont des valeurs entières exprimées
dans une unité donnée. Les formes doivent avoir des intersections vides.
8/57 .
Polymorphisme
Problème :
Si les affaires marchent bien, la scierie envisage d’étendre le système pour
découper des triangles, des ellipses, ...
9/57 .
10/57 .
Pattern GoF : Itérateur (1/3)
Problème :
L’équipe de développement hésite sur le choix de la structure de données à
utiliser pour mémoriser les formes du plan
11/57 .
Pattern GoF : Itérateur (2/3)
12/57 .
Pattern GoF : Itérateur (3/3)
13/57 .
Architecture Modèle-Vue-Contrôleur (MVC)
Problèmes :
L’utilisateur peut demander de changer la façon d’interagir avec PlaCo :
Ajouter un menu avec liste déroulante pour sélectionner une forme
à ajouter
Ajouter une description textuelle du plan, en plus de la visualisation
graphique
Changer la façon de saisir les informations pour ajouter une
nouvelle forme dans le plan
etc
La technologie utilisée pour la visualisation peut changer
La classe Plan perd en cohésion si elle doit s’occuper d’afficher le plan
Solution :
Architecture MVC !
14/57 .
Architecture Modèle-Vue-Contrôleur (MVC)
Modèle : Met à jour et traite les données "métier"
Ajoute/supprime/déplace des formes sur un plan
; Détermine si deux formes ont une intersection vide
17/57 .
Pattern GoF : Observateur (aka Publish/Subscribe) (1/2)
17/57 .
Pattern GoF : Observateur (aka Publish/Subscribe) (1/2)
17/57 .
Pattern GoF : Observateur (aka Publish/Subscribe) (1/2)
17/57 .
Pattern GoF : Observateur (aka Publish/Subscribe) (2/2)
Remarque :
Les données de Subject peuvent être “poussées” (dans notify) ou
“tirées” (avec des getters)
18/57 .
Observer et Observable “deprecated” dans Java 9
Pourquoi ?
notifyObservers ne spécifie pas l’ordre de notification
update ne connait pas la classe de l’objet Observable
Un objet Observable ne peut pas être sérialisé
Mais cela ne veut pas dire que le design pattern n’est pas bon !
On le retrouve dans les “Listeners”
Il peut être facilement implémenté (sans utiliser
[Link])
On peut utiliser PropertyChangeEvent et
PropertyChangeListener de [Link]
19/57 .
Pattern GoF : Visiteur (1/3)
Problème :
Perte de la classe effective des formes dans VueGraphique
Inconvénients :
Peut devenir lourd si
Forme a beaucoup de
sous-classes
Même problème pour
VueTextuelle
20/57 .
Pattern GoF : Visiteur (2/3)
21/57 .
Pattern GoF : Visiteur (2/3)
21/57 .
Pattern GoF : Visiteur (2/3)
21/57 .
Pattern GoF : Visiteur (3/3)
22/57 .
Architecture actuelle de PlaCo
23/57 .
Architecture actuelle de PlaCo
23/57 .
Comment déterminer les événements à écouter ?
24/57 .
Extraction des événements à partir des scénarios
Evénements utilisateurs :
Clic sur le bouton "Ajouter un rectangle"
Clic gauche de la souris sur la vue graphique du plan
Clic droit de la souris ou [Esc]
25/57 .
Extraction des événements à partir des scénarios
Evénements utilisateurs :
Clic sur le bouton "Ajouter un rectangle"
Clic gauche de la souris sur la vue graphique du plan
Clic droit de la souris ou [Esc]
25/57 .
Extraction des événements à partir des scénarios
Evénements utilisateurs :
Clic sur le bouton "Ajouter un rectangle"
Clic gauche de la souris sur la vue graphique du plan
Clic droit de la souris ou [Esc]
25/57 .
Extraction des événements à partir des scénarios
Evénements utilisateurs :
Clic sur le bouton "Ajouter un rectangle"
Clic gauche de la souris sur la vue graphique du plan
Clic droit de la souris ou [Esc]
25/57 .
Liste des événements utilisateur de PlaCo :
Clic sur un bouton : AjouterCercle, AjouterRectangle, . . . , Undo, Redo
Frappe d’une touche au clavier : flêches, [Ctr Z], [Shift Ctr Z], [Esc]
Clic gauche de la souris sur la vue graphique
Clic droit de la souris sur la vue graphique
Déplacement de la souris sur la vue graphique
27/57 .
Que fait Contrôleur ?
28/57 .
Diagramme Etats-Transitions de PlaCo
29/57 .
Diagramme Etats-Transitions de PlaCo
Solution 1 :
Contrôleur a un attribut
etatCourant mémorisant son état
clicGauche(p) contient un cas par
état possible
Avantages et inconvénients ?
32/57 .
Pattern GoF : Etat (State) (4/5)
Code de la méthode clicGauche :
Dans la classe Contrôleur
etc.
33/57 .
Pattern GoF : State (5/5)
Solution générique :
[Wikipedia]
34/57 .
Architecture actuelle de PlaCo)
Cde Ajout :
36/57 .
Pattern GoF : Commande (1/2)
36/57 .
Pattern GoF : Commande (1/2)
Undo/Redo :
36/57 .
Pattern GoF : Commande (2/2)
Solution générique :
Client crée les instances
de ConcreteCommand
Invoker demande
l’exécution des commandes
ConcreteCommande
délègue l’exécution à
Receiver
Remarques :
Découple la réception d’une requête de son exécution
Les rôles de Client et Invoker peuvent être joués par une même
classe (par exemple le contrôleur)
Permet la journalisation des requêtes pour reprise sur incident
Permet d’annuler ou ré-exécuter des requêtes (undo/redo)
37/57 .
Diagrammes de séquence (1/2)
Remarque :
clicGauche(fenetre,plan,cdes,p) est un message polymorphe
; Faire un diagramme de séquence pour chaque classe réalisant Etat
38/57 .
Diagrammes de séquence (2/2)
39/57 .
Patterns GoF : Poids Plume (FlyWeight) et Factory
Problème :
Nombreuses créations/destructions d’instances de Point
Solution :
Partager la même instance pour les points de mêmes coordonnées
; Attention : changer d’instance pour déplacer un point !
Utiliser une Factory pour créer/mémoriser les instances
40/57 .
Patterns GoF : Poids Plume (FlyWeight) et Factory
Problème :
Nombreuses créations/destructions d’instances de Point
Solution :
Partager la même instance pour les points de mêmes coordonnées
; Attention : changer d’instance pour déplacer un point !
Utiliser une Factory pour créer/mémoriser les instances
40/57 .
Patterns GoF : Poids Plume (FlyWeight) et Factory
Problème :
Nombreuses créations/destructions d’instances de Point
Solution :
Partager la même instance pour les points de mêmes coordonnées
; Attention : changer d’instance pour déplacer un point !
Utiliser une Factory pour créer/mémoriser les instances
40/57 .
Architecture actuelle de PlaCo
Utiliser un Singleton
42/57 .
Patron GoF : Singleton
Attention :
Parfois considéré comme un anti-pattern... à utiliser avec modération !
43/57 .
Plan du cours
1 Introduction
44/57 .
23 patrons du Gang of Four (GoF)
[E. Gamma, R. Helm, R. Johnson, J. Vlissides]
1 ...
AbstractGUIfactory Client AbstractGUIfactory f;
+créeBouton(...) if (..) f=new GUIfactoryOSX();
+créeMenu(...) else f=new GUIfactoryLinux();
...
Bouton b=[Link]éeBouton(...);
Menu m=[Link]éeMenu(...);
...
GUIfactoryOSX GUIfactoryLinux
public Bouton créeBouton(...){
+créeBouton(...) +créeBouton(...) return new BoutonLinux(...);
+créeMenu(...) +créeMenu(...) }
Bouton * * Menu
+dessine(...) +actionMenu(...)
46/57 .
Patron GoF : Abstract factory (2/2)
Remarques :
Solution Générique [Wikipedia] :
AbstractFactory et AbstractProduct
sont généralement des interfaces
; Programmer pour des interfaces
Les méthodes createProduct. . . ()
sont des factory methods
Avantages du pattern :
Indirection : Isole Client des
implémentations des produits
Protection des variations : Facilite la
substitution de familles de produits
Maintien automatique de la
cohérence
47/57 .
Patron GoF : Strategy (1/3)
Problème :
Changer dynamiquement le comportement d’un objet
48/57 .
Patron GoF : Strategy (1/3)
Problème :
Changer dynamiquement le comportement d’un objet
48/57 .
Patron GoF : Strategy (2/3)
Diagramme de classes de la solution 3 :
49/57 .
Patron GoF : Strategy (2/3)
Diagramme de classes de la solution 3 :
49/57 .
Patron GoF : Strategy (3/3)
Solution générique :
[Wikipedia]
Remarques :
Principes de conception orientée objet mobilisés :
Indirection : Isole Context des implémentations de Strategy
; Protection des variations
Composer au lieu d’hériter : Changer dynamiquement de stratégie
Passage d’informations de Context à Strategy
en “poussant” : l’info est un param de AlgorithmInterface()
en “tirant” : le contexte est un param. de AlgorithmInterface()
qui utilise des getters pour récupérer l’info
50/57 .
Patron GoF : Adaptateur
Problème :
Fournir une interface stable (Adaptateur) à un composant dont l’interface
peut varier (Adapté)
Solution générique :
Exercices :
Dessiner le diagramme de séquence de l’envoi du message
opClient() à une instance de Client
Comment faire s’il y a plusieurs composants (Adapté) différents, et que
l’on veut pouvoir choisir dynamiquement la classe adaptée ?
51/57 .
Patron GoF : Facade
Problème :
Fournir une interface simplifiée (Facade)
@override
Fromage Oignon Jambon public Jambon(Pizza p){
public double calcPrix(){ super(p);
return prixFromage calcPrix() calcPrix() calcPrix() }
+ [Link](); affDescr() affDescr() affDescr()
}
53/57 .
Patron GoF : Décorateur (2/2)
[Wikipedia]
54/57 .
Adaptateur, Facade et Décorateur
Points communs :
Indirection ; Enveloppe (wrapper)
Protection des variations
Différences :
Adaptateur : Convertit une interface en une autre (attendue par un
Client)
Facade : Fournit une interface simplifiée
Décorateur : Ajoute dynamiquement des responsabilités aux méthodes
d’une interface sans la modifier
55/57 .
Patron GoF : Composite (1/2)
Problème :
Représenter des hiérarchies composant/composé et traiter de façon uniforme
les composants et les composés
nombre de tags ?
56/57 .
Patron GoF : Composite (2/2)
Solution générique : *
Composant fils
attCommun
opCommune()
Feuille Composite
attCommun attCommun
... ...
opCommune() opCommune()
... ...
Exercices :
Définir les opérations permettant de :
Compter le nombre de fils d’un composant
Compter le nombre de descendants d’un composant
Ajouter un fils à un composant
Comment accéder séquentiellement aux fils d’un Composite ?
Comment accéder séquentiellement aux descendants d’un Composite ?
57/57 .