Strategy
Strategy
Strategy
(Design patterns)
1
Plan
2
Historique
Notion de « patron » d’abord apparue en architecture :
l’architecture des bâtiments
la conception des villes et de leur environnement
L’architecte Christopher Alexander le définit comme suit:
«Chaque modèle [patron] décrit un problème qui se manifeste constamment
dans notre environnement, et donc décrit le cœur de la solution de ce problème,
d’une façon telle que l’on peut réutiliser cette solution des millions de fois.» [Livre:
The Timeless Way of Building, Oxford University Press 1979]
5
Riadh BEN HALIMA [Design patterns]
Intérêt et utilisation des patrons de
conception
La meilleure manière d’utilisation des patrons de conception est de les mémoriser
en tête, puis reconnaitre leurs emplacements et les appliquer dans la conception
des applications
6
Riadh BEN HALIMA [Design patterns]
Ce qu’il ne faut pas attendre des patrons
de conception
7
Riadh BEN HALIMA [Design patterns]
Type des design patterns (1/4)
Creational
Design
Structural
Patterns
Behavioral
8
Riadh BEN HALIMA [Design patterns]
Type des design patterns (2/4)
Creational Design Patterns
9
Riadh BEN HALIMA [Design patterns]
Type des design patterns (3/4)
Structural Design Patterns
Ce sont des partterns qui facilitent le design en
identifiant un moyen simple pour mettre en place la
relation entre les entités
10
Riadh BEN HALIMA [Design patterns]
Type des design patterns (4/4)
Creational Patterns Structural Patterns Behavioral Patterns
Composite Template
Iterator
Method
Proxy
12
Riadh BEN HALIMA [Design patterns]
Le patron
"Strategy"
13
Riadh BEN HALIMA [Design patterns]
SimUDuck:
Conception (1/23)
Objectif: développement d’un jeu de simulation d’un bassin
pour les canards
Besoin: nager, cancaner, afficher, etc..
Supporter une large variété de canards
Conception: OO
Une supère classe Canard (Duck) dont tous les canards héritent
Duck
quack()
Abstract swim()
display()
display() display()
14
Riadh BEN HALIMA [Design patterns]
SimUDuck : Innovation (2/23)
Objectif: Innovation (pour impressionner et vendre +)
Besoin: simuler le vol des canards!
Conception: OO
Ajouter la méthode fly() à la supère classe
Duck
quack()
swim()
Modification apportée fly()
display()
display() display()
15
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Problèmes (3/23)
Besoin: Au moment de la démonstration du simulateur, on nous
demande de simuler des canards en caoutchouc
Conception: OO
Ajouter la classe RubberDuck qui hérite de la supère classe Duck
Duck
! Le caoutchouc ne vole pas
quack()
swim()
Hériter par tous les canards fly()
display()
display()
display() display()
quack(){
Redéfinir à squeak
}
16
? Le caoutchouc ne cancane pas
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Constat (4/23)
Problème 1: Le canard en caoutchouc ne cancane pas!
Solution : Redéfinir la méthode quack() à squeak()
(résolu)
Problème 2: Le canard en caoutchouc ne vole pas!
Toutefois, il hérite la méthode fly() de la supère classe
Duck!
Constat:
Ce que nous avons cru une utilisation formidable de l’héritage
dans le but de la réutilisation, s’est terminé mal au moment de
la mise à jour!
Une mise à jour du code a causé un effet global sur
l’application!
17
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Solution?? (5/23)
Problème 2: Le canard en caoutchouc ne vole pas! Toutefois, il
hérite la méthode fly() de la supère classe Duck!
Solution: Redéfinir la méthode fly() de RubberDuck
RubberDuck
display()
quack(){ squeak }
fly(){
Redéfinir à rien
}
18
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Un autre canard (6/23)
Nouveau type de canard: Canard en bois
Problèmes levés:
Ce canard ne cancane pas
Ce canard ne vole pas
Solution: redéfinir (une autre fois) les méthodes quack() et fly()
WoodenDuck
display()
quack(){
Redéfinir à rien
}
fly(){
Redéfinir à rien
}
Inconvénients de l’utilisation de l’héritage
Il est difficile de connaitre le comportement de tous les canards
Un changement non-intentionnel, affecte les autres canards
19
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Des interfaces? (7/23)
Hypothèse: On nous demande de mettre à jour SimUDuck tous les 6 mois: La
spécification demeure changeante
Vérifier fly() et quack() pour chaque nouveau canard
Ré-écrire (si besoin) fly() et quack()
Solution possible pour contourner le problème: les interfaces
Interface
Duck
Flyable Quackable swim()
fly() quack() display()
Constat:
Duplication de code: méthodes fly() et quack() dans les sous-classes
Autant d’interfaces tant qu’il y a un ensemble de canards ayant exclusivement un
comportement commun (pondre: lay() pour les canards qui peuvent déposer un œuf)
Problème: si on veut modifier/adapter légèrement la méthode fly(), il faut le faire
pour toutes les classes des canards (10 classes, 100, ou +)
21
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Moment de réflexion (9/23)
Pas toutes les sous-classes qui ont besoin de voler (fly)
ou de cancaner (quack)
L’héritage n’est pas la bonne solution
Les interfaces Flyable et Quackable résolvent une
partie du problème
Détruit complètement la réutilisation du code pour ces
comportements
La maintenance et la mise à jour représentent un vrai calvaire
Supposant qu’il existe plus qu’une façon de voler
Maintenance plus difficile…
22
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Solution (10/23)
Solution:
Design pattern : solution ultime, cheval blanc, sauveur…
Mise en œuvre
Prendre la partie qui varie et l’encapsuler. De cette
façon, un changement ultérieur affecte la partie
variable, sans toucher à celle invariable
24
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Séparation (12/23)
La classe Duck est toujours la supère classe
Les comportements fly() et quack() sont retirés, et mis dans une
autre structure
Comportements
Mettre dehors ce qui varie
Le comportement Quack
Invariable Variable
25
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Conception des comportements (13/23)
Conception initiale: l’inflexibilité des comportements a engendré
des troubles
On veut affecter les comportements aux instances des Ducks
tout en permettant:
La création d’une instance (MallardDuck),
L’initialisation avec un type de comportement (type de vol)
La possibilité de changer le type de vol dynamiquement (?)
27
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Intégration des comportements(15/23)
La supère classe Duck, dont hérite tous les canards
Duck Variable d’instance
du type INTERFACE
FlyBehavior fbehavior;
QuackBehavior qbehavior;
performQuack()
swim()
display()
performFly()
//….
29
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Implémentation d’un canard (17/23)
30
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Tester le code du canard(18/23)
Développer et compiler [Utiliser NetBeans/Eclipse]:
La classe abstraite Duck (Duck.java)
Le comportements: FlyBehavior.java, FlyWithWings.java et
FlyNoWay.java,
Le comportement : QuackBehavior.java, Quack.java, Squeak.java et
MuteQuack.java
Les classes MallardDuck.java et WoodenDuck.java
Tester toutes les méthodes des canards créés dans un main:
MallardDuckSim.java
31
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Le comportement dynamique (19/23)
Changement dynamique de comportement
Ajouter les méthodes: setFlyBehavior() et setQuackBehavior()
Développer le canard RedHeadDuck (RedHeadDuck.java)
Implanter le nouveau comportement "vole-force-fusée"
FlyRocketPowered (FlyRocketPowered.java)
Tester le nouveau canard dans un main RedHeadSim.java
Changer le comportement "voler" de FlyWithWings à
FlyRocketPowered. Penser à utiliser le setter afin d’obtenir ces
deux affichages: "Je peux voler" & "Je vole comme une fusée"
34
Riadh BEN HALIMA [Design patterns]
SimUDuck :
Notre premier patron (22/23)
35
Riadh BEN HALIMA [Design patterns]
Diagramme de classes du patron (23/23)
strategy <<interface>>
Context
Strategy
ContextInterface() AlgorithmInterface()
Première implémentation du
comportement Deuxième implémentation du
comportement
36
Riadh BEN HALIMA [Design patterns]
Récapitulatif (1/2)
Bases de l’OO:
Abstraction, Encapsulation, Polymorphisme & Héritage
Principes de l’OO
Encapsuler ce qui varie
Favoriser la composition sur l’héritage
Programmer avec des interfaces et non des implémentations
Patron de l’OO (stratégie)
Le patron stratégie définit une famille d’algorithmes, les
encapsule, et les rend interchangeable. Ce patron laisse
l’algorithme varier indépendamment du client qu’il l’utilise.
37
Riadh BEN HALIMA [Design patterns]
Récapitulatif (2/2)
Connaitre les bases de l’OO ne fait pas de toi un bon concepteur
Les meilleurs conception OO sont réutilisable, flexible et
maintenable
Les patrons nous guident à construire des systèmes avec les bonnes
qualités de la conception OO
Les patrons sont des expériences prouvées dans l’OO
Les patrons ne donnent pas de code, mais plutôt des solutions
générales pour des problèmes de conception
Les patrons de sont pas inventés, mais découverts
La majorité des patrons et des principes adresses les problèmes de
changement dans le logiciel
On essaie toujours de prendre ce qui varie des systèmes et on
l’encapsule
Les patrons offrent un langage partagé qui peut maximiser la valeur
de la communication avec les autres développeurs
38
Riadh BEN HALIMA [Design patterns]
Exercice (1/2)
Ci-dessous, on donne l’ensemble de classes et interfaces d’un jeu
d’action et d’aventure. Il y a des classes d’individus avec des
classes pour les comportements d’armes que les individus
peuvent utiliser. Chaque individu peut utiliser une seule arme à la
fois, mais peut la changer à tout moment durant le jeu. La tâche
demandée est d’ordonner le tout.
Individu ComportementCouteau Chevalier
ComportementArme arme; utiliseArme(){\\abattre avec display(){….}
combattre() couteau }
display ()
Archer ComportementArcFleche
Reine
display(){….} utiliseArme(){\\abattre avec arc
display(){….} et flèche}
ComportementArme
setArme(ComportementArme ca) {
utiliseArme();
this.arme=ca; ComportementEpee
}
utiliseArme(){\\abattre avec
39 épée}
Riadh BEN HALIMA [Design patterns]
Exercice (2/2)
1. Arranger les classes
2. Identifier les classes, les classes abstraites des interfaces
3. Relier les entités pas des flèches ou:
1. représente extends
2. représente implements
3. représente has-a
4. Mettre la méthode setArme() dans la classe
correspondante
5. Implémenter et tester cette conception dans un main.
Penser à changer dynamiquement le comportement de
l’archer après avoir finir ces arcs.
40
Riadh BEN HALIMA [Design patterns]
Le patron
"Observer"
41
Riadh BEN HALIMA [Design patterns]
Station météo:
Spécification (1/14)
Objectif: Construire une nouvelles génération de stations
d’observation météo sur Internet
Besoin: Afficher les conditions courantes, les statistiques
météorologique et les prévisions météo.
Poursuivre les conditions météorologiques (Température,
Humidité, Pression, etc.)
On veut mettre en œuvre une API (ENIS-METEO) de façon
que d’autres développeurs peuvent écrire leur propre afficheur
de météo.
Conception: OO
Une classe WeatherData qui récupère les données de la station
météo (ENIS-METEO) et les offre aux afficheurs.
42
Riadh BEN HALIMA [Design patterns]
Station météo:
Analyse (2/14)
Afficher
Capteur
d’humidité Tirer (pull)
Capteur de
température
Weather Station
WeatherData
Object
Capteur de Conditions
pression courantes
45
Riadh BEN HALIMA [Design patterns]
Station météo:
Constat (5/14)
Problème : En codant des implémentations concrètes, on ne peut pas
ajouter/supprimer d’autres afficheurs, sans faire un changement du
programme!
Rq: on peut au moins utiliser une interface qui contient la
méthode update()
Solution : le patron observer
Exemple:
1. Une maison d’édition commence l’édition d’un journal
2. Vous vous inscrivez à ce journal, et pour chaque nouvelle
édition, vous recevez votre copie
3. Vous vous désinscrivez lorsque vous ne voulez plus recevoir
des journaux
4. Les gens, les hôtels etc. peuvent constamment s’inscrire et se
désinscrire à ce journal
46
Riadh BEN HALIMA [Design patterns]
Station météo:
Publier/Souscrire= Patron Observer (6/14)
Les observers sont
inscrits au Sujet afin de
Lorsque les données du sujet changent, recevoir les mise à jour
les observateurs sont notifiés
L’objet Sujet gère des
octets de données
2
47
Riadh BEN HALIMA [Design patterns]
Station météo:
Patron Observer : S’inscrire (7/14)
48
Riadh BEN HALIMA [Design patterns]
Station météo:
Patron Observer : Notification(8/14)
Maintenant, le Mouse est un
observer, il reçoit les
notifications du Sujet
Nouvel entier
49
Riadh BEN HALIMA [Design patterns]
Station météo:
Patron Observer : Désinscrire (9/14)
50
Riadh BEN HALIMA [Design patterns]
Station météo:
Patron Observer : Notification (10/14)
Maintenant, le Dog n’est plus un
observer, il ne reçoit plus les
notifications du Sujet
12
12
Nouvel entier
51
Riadh BEN HALIMA [Design patterns]
Station météo:
Le patron Observer (11/14)
Définition: Observer
Le patron observer définit une dépendance 1-à-plusieurs
entre des objets de façon que à chaque changement de
l’état de l’objet, tous ces dépendants sont notifiés et mis à
jour automatiquement.
1-à-plusieurs
8
8
ConcreteSubject ConcreteObserver
Le ConcreteSubject registerObserver(..){…} update(..)
hérite toujours de removeObserver(..) {…} //autres méthodes
l’interface Subject. Il
notifyObservers() {…}
implémente la méthode
notifyObservers() qui
est sensée mettre à getState()
Toutes classes qui implémente l’observer est
jour l’observer quand setState() un observer concret. Chaque observer
l’état change. concret s’inscrit auprès d’un sujet concret
pour recevoir l’update
53
Riadh BEN HALIMA [Design patterns]
Station météo:
La puissance du couplage faible (13/14)
Deux objets, qui sont faiblement couplés, entrent en interaction
avec très peu de connaissance de l’un envers l’autre.
Le patron Observer permet de réaliser une conception ou le
Subject et l’Observer sont faiblement couplés
Couplage faible : plus d’indépendance et de flexibilité
La seule chose que le Subject a besoin de connaitre sur l’Observer est
qu’il implémente une certaine interface.
On peut ajouter/remplacer/supprimer un observer à tout moment
sans toucher au Subject
On peut réutiliser le Subject ou l’Observer facilement parce qu’ils ne
sont pas fortement couplés.
La modification du Subject ou de l’Observer n’affecte pas l’autre classe
Règle 4: Opter pour une conception faiblement couplée
entre les objets qui interagissent
54
Riadh BEN HALIMA [Design patterns]
Station météo:
La conception finale (14/14)
observers
<<interface>> <<interface>>
Subject Observer
registerObserver(..) * update(…)
removeObserver(..) display()
notifyObservers()
CurrentConditionsDisplay
WeatherData update(…)
display()
registerObserver(..){…}
removeObserver(..) {…}
notifyObservers() {…}
StatisticsDisplay ForecastDisplay
getTemperature()
getHumidity() update(…) update(…)
getPressure() display() display()
measurementChanged()
56
Riadh BEN HALIMA [Design patterns]
Récapitulatif (2/2)
Le patron observer définit une relation 1-à-plusieurs entre
objets.
Le Subject/Observable met à jour les observers à travers
une interface commune.
L’observer est faiblement couplé avec le Subject. Ce
dernier ne connait rien d’eux à part qu’ils implémentent
l’interface Observer.
On peut récupérer les données du Subject en mode
pull/push. (Le Subject fait le push, semble plus correct)
On ne dépend pas d’un ordre spécifique de notification
entre les observers
Java possède plusieurs implémentations de ce patron
57
Riadh BEN HALIMA [Design patterns]
Exercice 1
1. Appliquer le patron Observer sur l’application station météo en se
basant sur les implémentations du Subject et de l’Observer offertes
par Java :
java.util.Observable : Subject du patron (Attention! Il s’agit d’une classe)
java.util.Observer : Observer du patron
<<interface>>
Pour dire Observable Observer
explicitement que
l’état de l’observable addObserver(Observer o) update(Observable o, Object
a changé. Elle ne fait deleteObserver(Observer o) arg)
pas la notification. notifyObservers(Object arg)
setChanged() Ou
o est utilisé pour récupérer le message, et
arg est un argument à passer à l’observer
Il s’agit d’une classe. Les méthodes (mettez le à null, si pas besoin de passer un argument)
offertes sont déjà implémentées.
ding()
afficheTempsEcoule()
59
Riadh BEN HALIMA [Design patterns]
Exercice2 (2/2)
Utiliser le pattern Observer pour définir les interactions entre Chrono, Display et
Sonnerie
Donnez le diagramme de classes et l’implémentation tout en considérant le
programme principal suivant:
61
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Spécification (1/10)
Objectif: Mettre en œuvre un système de gestion des offres
de boisson pour la clientèle de StarCoffee
Besoin: Décrire les ajouts en extra, et calculer le prix total
Thé, Thé-à-la-menthe, Thé-à-la-mente-aux-pignons, etc..
Café, Café-au-Lait, Café-au-Lait-à-la-mousse, etc..
Conception: OO
Concevoir une supère classe Boisson que toutes les autres
classes héritent.
Définir autant de classes qu’il y en a de types de boissons :
Beverage.java, Coffee.java, CoffeeWithMilk.java,
CoffeeWithMilkWithWhip.java, Tea.java, TeaWithMint.java,
TeaWithMintWithPine.java, etc.
62
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Conception (2/10)
Beverage Retourne la description
Méthode abstraite à définir Description
dans les classes dérivées getDescription()
cost()
Tea
Coffee
cost()
cost() CoffeeWithMilk
TeaWithMint
cost()
CoffeeWithMilk cost()
WithWhip
TeaWithMintWit
cost() hPine
cost()
Coffee Tea
cost() cost()
65
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Un boisson décoré (5/10)
1. On commence par l’objet Tea
La classe Tea hérite de Beverage et possède une
cost() méthode cost() qui calcule le prix du boisson
67
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Le coût du boisson décoré (7/10)
L’idée est de calculer le coût en partant du décorateur le plus extérieur
(Pine) et puis, ce dernier délègue le calcul à l’objet décoré, etc.
Pine appelle cost() de Mint
Invocation de la méthode Mint appelle cost() de Tea
cost() du décorateur extérieur
1.000
Pine ajoute son prix au résultat de Tea retourne son prix: 0.500
Mint, et retourne le résultat total: 1.000
Mint ajoute son prix au résultat de cost()
de Tea, et retourne le nouveau total: 0.700
68
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Le patron Decorator (8/10)
Définition: Decorator
Le patron decorator attache des responsabilités
additionnelles à un objet dynamiquement. Les décorateurs
offrent une alternative flexible de sous-classement afin
d’étendre les fonctionnalités.
69
Riadh BEN HALIMA [Design patterns]
StarCoffee :
Le diagramme de classes du patron(9/10)
Chaque composant peut être utilisé à lui
Component seul, ou enveloppé dans des décorateurs
methodA()
methodB() Chaque décorateur possède un composant, qui veut
Le ConcreteComponent est dire que le décorateur possède un attribut qui contient
l’objet qu’on va lui ajouter //autres méthodes une référence d’un composant
dynamiquement des nouveaux
comportements. Il étend
l’objet Component.
ConcreteComponent Decorator
ConcreteDecoratorA ConcreteDecoratorB
Le ConcreteDecorator possède
un attribut qui représente l’objet Component WrappedObj Component WrappedObj
qu’il décore. Il peut ajouter ses Object newState
propres méthodes et attributs. methodA()
methodB() methodA()
Newbehavior() methodB()
70
//autres méthodes //autres méthodes
Riadh BEN HALIMA [Design patterns]
StarCoffee :
La conception finale (10/10)
Beverage
Beverage agit comme notre
classe abstraite component description
getDescription()
cost();
//autres méthodes
71
Riadh BEN HALIMA [Design patterns]
Récapitulatif (1/2)
Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage
Principes de l’OO
Encapsuler ce qui varie
Favoriser la composition sur l’héritage
Programmer avec des interfaces et non des implémentations
Opter pour une conception faiblement couplée
Les classes doivent être ouvertes pour les extensions et fermées pour
les modifications
Patron de l’OO
Strategy: définit une famille d’algorithmes interchangeables
Observer: définit une dépendance1-à-plusieurs entre objets.
decorator: attache des responsabilités additionnelles à un objet
dynamiquement. Les décorateurs offrent une alternative flexible de sous-
classement afin d’étendre les fonctionnalités.
72
Riadh BEN HALIMA [Design patterns]
Récapitulatif (2/2)
L’héritage est une forme d’extension, mais il n’est pas nécessairement
la meilleure manière pour obtenir la flexibilité dans notre conception
Le patron decorator implique un ensemble de classes de décorations
qui sont utilisées pour envelopper les composants concrets.
Les classes décorateurs reflètent le type de composant qu’ils
décorent.
Les décorateurs changent le comportement de leurs composants tout
en ajoutant des nouvelles fonctionnalités après/avant (ou à la place de)
l’appel des méthodes des composants
On peut envelopper un composant dans n’importe quel nombre de
décorateurs
Les décorateurs sont transparents par rapport au client du
composant
73
Riadh BEN HALIMA [Design patterns]
Exercice (1/5)
1. Comment faire pour obtenir un café avec "double mousse"?
2. StarCoffee a ajouté un nouveau boisson (Citronnade) au système,
comment procéder pour l’inclure dans la conception actuelle?
3. StarCoffee veut introduire des tailles pour ses menus: SMALL,
MEDIUM et LARGE. Comment prendre en charge cette nouvelle
spécification, si la taille modifie seulement les prix des composants
concrets?
74
Riadh BEN HALIMA [Design patterns]
Exercice (2/5)
Avec le patron decorator, le package java.io doit donner plus de
sens, puisqu’il se base largement sur ce patron.
75
Riadh BEN HALIMA [Design patterns]
Exercice (3/5): Décoration de java.io
1. Ecrire un décorateur qui convertit tous les caractères majuscules
en minuscules dans le flux d’entrée (InputStream).
Abstract Component
Conctrete
Component InputStream
Abstract Decorator
ByteArrayInputStream
PushBackInputStream BufferedInputStream
Decorator
DataInputStream LineNumberInputStream
76
Riadh BEN HALIMA [Design patterns]
Exercice (4/5)
L’objectif de cet exercice est de mettre en œuvre un système
flexible de gestion des offres de voiture pour la clientèle de
StarCar. Le besoin de cette société se résume à décrire les
options demandées par le client (VitreElectrique, AirBag et ABS)
et inclure son cout au prix total de la voiture choisie. Deux types
de voiture sont gérés par la société, à savoir, camionnette et
berline. Chaque voiture est caractérisée par un cout et une
description textuelle. Le prix de chaque type de voiture ainsi que
celui de chaque option est à fixer au moment de la création.
En utilisant le patron Decorator, donnez le diagramme de classes
de l’application CarStar. (Précisez les méthodes et les attributs,
correspondant au bout de code présenté dans le slide suivant)
77
Riadh BEN HALIMA [Design patterns]
Exercice (5/5)
public static void main(String[] args) {
Voiture v1=new Camionnette ("P404",10000);
Voiture v2=new Berline ("P407",20000);
v1=new ABS(v1, 800);//800 représente le prix de l’option ABS
v2=new VitreElectrique(v2, 1000); // 1000 représente le prix de l’option
v2=new AirBag(v2, 1200); // 1200 représente le prix de l’option
System.out.println("La voiture est une "+v1.getDescription());
//affiche: La voiture est une P404 avec ABS
System.out.println("Son prix est:"+ v1.cost());
//affiche: Son prix est 10800
System.out.println("La voiture est une "+v2.getDescription());
//affiche: La voiture est une P407 avec VitreElectrique avec AirBag
System.out.println("Son prix est:"+ v2.cost());
//affiche: Son prix est 22200
78
Riadh BEN HALIMA [Design patterns]
Le patron
"Factory"
79
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Créer des pizzas (1/37)
Pizzeria: Créer des pizzas
Pour la flexibilité, on veut que
Pizza orderPizza(){ celui-ci soit une classe abstraite ou
Pizza pizza=new Pizza(); interface, sauf qu’on ne peut pas
instancier l’un des deux derniers!
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
80
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Plusieurs types de pizza (2/37)
Pizzeria: Créer plusieurs types de pizza
On passe le type du pizza à travers
Pizza orderPizza( String type ){
le méthode orderPizza()
Pizza pizza;
if (type.equals("cheese"){
pizza=new CheesePizza();
} else if (type.equals("greek"){ Selon le type de pizza, on crée la
pizza=new GreekPizza(); pizza concrète, et on la place dans
} else if (type.equals("pepperoni"){ la variable "pizza" (interface et
pizza=new PepperoniPizza(); classe mère des pizzas).
}
pizza.prepare();
pizza.bake(); Une fois on a la pizza, on prépare la sauce, le
pizza.cut(); nappage (tomate/crême fraiche) et le fromage ,
pizza.box(); puis on la fait cuire, la coupe, et on la met dans
return pizza; une boite.
}
81
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Autres types de pizza (3/37)
Les concurrents ont ajouté un nouveau type de pizza: (avec Calamars)
Ajouter ClamPizza au menu
On n’a pas vendu beaucoup de GreekPizza dernièrement
Suspendre GreekPizza du menu
Pizza orderPizza(String type){
Pizza pizza;
if (type.equals("cheese"){
Ce code est NON fermé
pizza=new CheesePizza();
pour la modification!
83 On attribue le nom
RiadhFactory à ce nouvel
BEN HALIMA objet
[Design patterns]
PizzaStore :
Un Simple Factory (5/37)
Le seul rôle de SimplePizzaFactory est de créer des pizzas pour ces
clients
Initialement, on définit la méthode
createPizza() dans le Factory. C’est la
public class SimplePizzaFactory { méthode que tous les clients utilisent
public Pizza createPizza(String type){ pour instancier des nouveaux objets.
Pizza pizza=null;
if (type.equals("cheese"){
pizza=new CheesePizza();
} else if (type.equals("pepperoni"){
pizza=new PepperoniPizza();
} else if (type.equals("clam"){
pizza=new ClamPizza();
} C’est le code qu’on a retirer de la
méthode orderPizza().
return pizza;
}
}
84
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Retravaillons la classe PizzaStore (6/37)
Maintenant, PizzaStore utilise SimplePizzaFactory pour créer des pizzas
PizzaStore récupère la
public class PizzaStore {
référence du factory à
private SimplePizzaFactory factory;
travers le constructeur.
public PizzaStore(SimplePizzaFactory factory){
this.factory=factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza=factory.createPizza(type);
pizza.prepare();
pizza.bake(); La méthode orderPizza() utilise le
pizza.cut(); factory pour créer ses pizzas.
pizza.box();
return pizza;
}
}
Noter qu’on a remplacé l’opérateur new par une méthode concrète
Plus d’instanciation concrète ici
85
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Le diagramme de classes (7/37)
Elle doit être la seule partie de On définit Pizza comme
notre application qui pointe vers les classe abstraite, avec quelque
classes des pizzas concrètes implémentations qui peuvent
être redéfinies
PizzaStore SimplePizzaFactory Pizza
prepare()
orderPizza() createPizza() bake()
cut()
box()
La méthode de création
est souvent statique
CheesePizza ClamPizza
PizzaStore crée des PepperoniPizza
instances à travers
SimplePizzaFactory
87
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Franchise de PizzaStore (8/37)
Objectif: Franchiser PizzaStore: Créer plusieurs stores dans
plusieurs villes (Sfax, Tunis, etc.)
Besoin: Développer une application qui gère la création des
pizzas pour chaque store
Chaque store offre différent types de pizza
Conception: OO
Moins de fromage dans
les pizzas, etc.
89
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Le framework de PizzaStore (10/37)
On donne la liberté aux franchises de créer leurs propres styles
Déplacer la création dans une la méthode createPizza() et garder la
même méthode orderPizza() pour tous les stores
Chaque région l’étend afin de spécifier son propre style
public abstract class PizzaStore {
91
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Un PizzaStore de Style Sfaxien (12/37)
Les bénéfices d’une franchise
On obtient des fonctionnalités des pizzas communes (prepare(), bake(), cut() et box())
Chaque région définit sa propre méthode createPizza() qui spécifie son style de pizza
public class SfaxStylePizzaStore extends PizzaStore {
Pizza createPizza(String type) {
Pizza pizza=null; On hérite la méthode
if ("cheese".equals(type)){ orderPizza() de PizzaStore
pizza=new SfaxStyleCheesePizza();
} else if ("pepperoni".equals(type)){ On implémente createPizza()
pizza=new SfaxStylePepperoniPizza(); puisqu’elle est abstraite:
} else if ("clam".equals(type)){ C’est la "méthode Factory"
pizza=new SfaxStyleClamPizza();
}
return pizza; Créer des pizzas du style sfaxien!!
}
Rq: Toutes les responsabilités d’instanciation sont déplacées vers la méthode
createPizza() qui agit comme un factory
La méthode factory gère la création des objets et leur encapsulation
Découplage du code du client dans la supère classe de la création de l’objet dans les sous-
classes
92
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Commander des pizzas (13/37)
Je voudrai une pizza Je voudrai une pizza
de grande taille avec beaucoup de taille moyenne avec
de fromage du style peu de fromage et au thon
tunisien du style sfaxien
tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");
On termine la préparation
pizza.prepare(); pizza.prepare();
pizza.bake(); pizza.bake();
pizza.cut(); pizza.cut();
pizza.box(); pizza.box();
94
De style tunisien DeRiadh
styleBEN
sfaxien
HALIMA [Design patterns]
PizzaStore :
Implémenter (15/37) Les créateurs
PizzaStore
Implémenter les classes: createPizza()
PizzaStore.java, SfaxPizzaStore.java orderPizza()
Factory Method
et TunisPizzaStore.java
SfaxStylePizzaStore TunisStylePizzaStore
createPizza() createPizza()
SfaxStylePepperoniPizza
TunisStylePepperoniPizza
95
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Le patron Factory Method (16/37)
96
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Le diagramme de classes du patron (17/37)
La classe mère de tous les produits Le Creator est une classe qui contient
concrets. Elle représente aussi le type l’implémentation de toutes les
générique qui référence vers les méthodes qui manipulent le produits,
instances des classes concrètes à l’exception de factoryMethod()
Le ConcretCreator
implémente la méthode
factoryMethod(), qui produit
ConcretProduct ConctretCreator les produits
factoryMethod()
La décision: choix
Le ConcretCreator est responsable de la création de produits du produit concret
concrets. C’est la classe qui connait le qui a créé chaque produit
97
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Un PizzaStore dépendant (18/37)
Hypothèse: On n’a jamais entendu parler du factory
Compter le nombre d’objets de pizzas concrètes dont cette classe dépend
Refaire le compte si on ajoute des pizzas de style bizertin
public class DependentPizzaStore {
Pizza createPizza(String style, String type) {
Pizza pizza=null;
if (style.equals("Sfax")){ Gérer toutes les pizzas de
if (type.equals("cheese"){
pizza=new SfaxStyleCheesePizza();
style sfaxien
} else if (type.equals("pepperoni"){
pizza=new SfaxStylePepperoniPizza();
} else if (type.equals("clam"){
pizza=new SfaxStyleClamPizza();
}
} else if (style.equals("Tunis")){
if (type.equals("cheese"){ Gérer toutes les pizzas de
pizza=new TunisStyleCheesePizza(); style tunisois
} else if (type.equals("pepperoni"){
pizza=new TunisStylePepperoniPizza();
} else if (type.equals("clam"){
pizza=new TunisStyleClamPizza();
}
} else {System.out.println("Erreur: type de pizza invalide");}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
98 }
} Riadh BEN HALIMA [Design patterns]
PizzaStore :
La dépendance entre les objets (19/37)
Cette version de PizzaStore dépend de tous les objets pizzas parce qu’elle les crée
directement
On dit que PizzaStore dépend des implémentations des pizzas parce que chaque
changement des implémentations concrètes des pizzas, affecte le PizzaStore
Si les implémentations des pizzas
changent, on doit modifier PizzaStore
100
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Appliquons ce principe (21/37)
PizzaStore dépend seulement de
Pizza, qui est une classe abstraite
Pizza est une classe
abstraite.. abstraction
Les classes de pizzas concrètes dépendent
aussi de l’abstraction Pizza, parce qu’elles
implémentent l’interface Pizza
Le "Factory Method"
est la technique la plus
puissante d’adhérence
au principe d’inversion
de dépendance, mais
pas la seule...
101
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Les ingrédients des pizzas (22/37)
Problème : quelques franchises n’ont pas utilisé la
même procédure de préparation, et ce en substituant
des ingrédients par d’autres de basse qualité, afin
d’augmenter leur marge.
! Il faut assurer la consistance des ingrédients
Sfax Tunis
Pizza Menu Pizza Menu
Nous avons les mêmes
Cheese Pizza Cheese Pizza
Sauce marinara, Parmesan,
familles de produits, mais
différente implémentations Sauce tomate prune, Mozzarella,
Emmental Roquefort
selon la région
Clam Pizza Clam Pizza
Sauce marinara, Parmesan, Sauce tomate prune, Mozzarella,
Clovis, Olive verte Palourde, Olive noire
Pepperoni Pizza Pepperoni Pizza
Sauce marinara, Parmesan, Sauce tomate prune, Mozzarella,
Aubergine, Poivron, Olive verte Épinard, Poivre, Olive noire
103
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Les familles des ingrédients (24/37)
Chaque famille correspond à un Tunis
type de sauce, un type de
fromage, un type de légume, et un PlumTomatoSauce
Mozzarella
type d’olive (et d’autres types)
Spinach
BlackOlive
Sfax
MarinaraSauce
Parmesan
104
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Les factories des ingrédients (25/37)
Le factory est le responsable de la création de la pâte, la sauce,
le fromage, etc.
Pour chaque ingrédient, on
public interface PizzaIngredientFactory {
crée une create() méthode
Dough createDough();
dans notre interface
Sauce createSauce();
Cheese createCheese();
Veggies[] createVeggies();
Clam createClam();
} Beaucoup de nouvelles
classes, une par ingredient
A faire :
Construire un facotry pour chaque région: une sous-classe de
PizzaIngredientFactory qui implémente chaque create() méthode
Implémenter un ensemble de classes d’ingrédients, à utiliser par les
factories tels que: OliveVerte, Mozzarella, SauseMarinara, etc.
Lier ceci avec notre ancien code de PizzaStore, tout en travaillant
nos factories d’ingrédients
105
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Les factories de Sfax (26/37)
109
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Retravaillons les classes des Pizzas (29/37)
110
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Retravaillons les PizzaStores (30/37)
Le store de Sfax est composé d’un
factory sfaxien d’ingrédients/
public class SfaxPizzaStore extends PizzaStore {
private PizzaIngredientFactory sfaxIngredientfactory =
new SfaxPizzaIngredientFactory();
@Override
public Pizza createPizza(String item) {
Pizza pizza = null; On passe à chaque pizza le factory
if (item.equals("cheese")){ censé créer ses ingrédients
pizza = new CheesePizza(sfaxIngredientfactory);
pizza.setName("Sfax Style Cheese Pizza");
} else if (item.equals("pepperoni")){
pizza = new PepperoniPizza(sfaxIngredientfactory);
pizza.setName("Sfax Style Pepperoni Pizza");
} else if (item.equals("clam")){
pizza = new ClamPizza(sfaxIngredientfactory);
pizza.setName("Sfax Style Clam Pizza");
}
return pizza;
}
}
111
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Factories (31/37)
Définit l’interface
Offre les
Abstract Ingredient Factory
implémentations
des ingrédients
Sfax Tunis
tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");
La méthode prepare() est appelée et chaque factory est appelé pour produire les
ingrédients de la région
115
De style tunisien DeRiadh
styleBEN
sfaxien
HALIMA [Design patterns]
PizzaStore :
Le patron Abstract Factory (35/37)
116
Riadh BEN HALIMA [Design patterns]
PizzaStore :
Le diagramme de classes du patron (36/37)
Le client est composé au moment de
l’exécution par un factory concret
L’abstract factory définit un Client
ensemble de méthodes pour la
production des produits Une famille de produits
<<interface>>
AbstractProductA
<<interface>>
AbstractFactory
createProductA()
createProductB()
ProductA2 ProductA1
<<interface>>
AbstractProductB
ConcretFactory1 ConcretFactory2
createProductA() createProductA()
createProductB() createProductB() ProductB2 ProductB1
Les factories concrets implémentent les
différences familles de produits
117
Riadh BEN HALIMA [Design patterns]
PizzaStore :
La conception finale (37/37) Les clients de l’abstract factory
sont les stores de Sfax et de Tunis
SfaxPizzaStore
L’abstract factory définit un <<interface>>
l’ensemble des produits qu’on a Clam
besoin pour faire une pizza
MarinaraSauce PlumTomatoSauce
121
Riadh BEN HALIMA [Design patterns]
Singleton :
Spécification (1/12)
Objectif: Créer un type d’objet pour lequel on crée
seulement une seule instance
C’est le patron ayant le diagramme de classes le plus simple
Il y a plusieurs objets dont on a besoin d’une seule instance:
pool d’impression, boite de dialogue, objet qui manipule les
préférences, objet de logging, objet agissant comme pilote de
carte graphique/imprimante…
La création de plus d’une instance de ces objets est une
source de problème, telle que la sur-utilisation des
ressources, des comportements incorrectes de programme,
des résultats inconsistants, etc.
122
Riadh BEN HALIMA [Design patterns]
Singleton :
Créer un singleton (2/12)
Comment créer un seul objet?
New MonObjet()
Et si un autre objet veut créer un MonObjet? Est-ce qu’il peut
appeler new sur MonObjet une autre fois?
Oui
Pour toute classe, est ce qu’on peut l’instancier plus qu’une fois?
Oui (il faut que la classe soit publique)
Que signifie ce code ?
public class MonObjet{
C’est une classe qui ne peut pas être instanciée, private MonObjet() {}
car elle possède un constructeur privé }
123
Riadh BEN HALIMA [Design patterns]
Singleton :
Créer un singleton (3/12)
Comment je peux appeler cette méthode (pour créer une
instance) si je n’ai pas d’instance?
static public class MonObjet{
Que signifie ce code. public static MonObjet getInstance() {
}
}
C’est une méthode statique qui peut être appelée à partir du nom de la
classe : MonObjet.getInstance()
Si on met les choses ensemble, est ce qu’on peut instancier
MonObjet? public class MonObjet{
private MonObjet(){ }
public static MonObjet getInstance() {
return new MonObjet();
}
}
Comment faire pour créer une seule instance?
124
Riadh BEN HALIMA [Design patterns]
Singleton :
Implémentation du patron (4/12)
Nous avons une variable statique
pour stocker notre instance
125
Riadh BEN HALIMA [Design patterns]
Singleton :
L’usine de chocolat (5/12)
public class ChocolateBoiler{
private boolean empty; Le code démarre lorsque
private boolean boiled; la casserole est vide
public ChocolateBoiler() {
empty=true; boiled=false;
Pour remplir la casserole, elle
}
public void fill(){ doit être vide. Lorsqu’elle est
if (empty){ pleine, on met empty à false.
//remplir la casserole avec du lait/chocolat
empty=false; boiled=false;
}
} Pour mixer le contenu de la
public void boil(){ casserole, elle doit être pleine et
if (!empty && !boiled){ non déjà mixée. Lorsqu’elle est
//faire bouillir pleine, on met boiled à true.
boiled=true;
}
}
public void drain(){ Pour vide la casserole, elle doit
if (!empty && boiled){ être pleine et déjà mixée. une
//vider la casserole fois vidée, on met empty à true.
empty=true;
}
}
}
126
Riadh BEN HALIMA [Design patterns]
Singleton :
L’usine de chocolat (6/12)
Améliorer le code de l’usine de chocolat en le transformant en Singleton
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
private static ChocolateBoiler uniqueInstance;
private ChocolateBoiler() {
empty=true; boiled=false;
}
127
Riadh BEN HALIMA [Design patterns]
Singleton :
Le patron Singleton(7/12)
Définition: Singleton
Le patron Singleton assure une seule instance pour une
classe, et offre un point d’accès global à cette classe.
128
Riadh BEN HALIMA [Design patterns]
Singleton:
Le diagramme de classes du patron (8/12)
Singleton
- static uniqueInstance
//autre données utiles
+ static getInstance()
//autre méthodes utiles
La méthode getInstance() est statique.
C’est une méthode de classe qu’on peut
y accéder partout dans le code avec
Singleton.getInstance(). Il s’agit d’une
instanciation facile de cette classe
129
Riadh BEN HALIMA [Design patterns]
Singleton :
Problème des threads (9/12)
Supposant que nous avons deux threads qui vont exécuter la méthode
getInstance(). Est-ce qu’il y a un cas où on crée 2 instances?
Thread-1 Thread-2 Valeur de
uniqueInstance
public static ChocolateBoiler
getInstance() null
public static ChocolateBoiler null
getInstance()
130
Riadh BEN HALIMA [Design patterns]
Singleton :
Gestion du multi-threading (10/12)
Solution 1: synchroniser l’accès à la méthode getInstance()
return uniqueInstance;
}
//autre méthodes utiles
}
private Singleton() {}
private Singleton() {}
134
Riadh BEN HALIMA [Design patterns]
Récapitulatif (2/2)
Le patron singleton assure la création d’au plus une instance d’une
classe de notre application
Le patron offre aussi un seul point d’accès global à cette instance
L’implémentation Java du patron utilise un constructeur privé une
méthode statique combinée avec une variable statique
Le développeur examine la performance et les contraintes des
ressources et choisit soigneusement une implémentation pour une
application multi-thread
135
Riadh BEN HALIMA [Design patterns]
Le patron
"Adapter"
136
Riadh BEN HALIMA [Design patterns]
Le patron adapter :
Les adaptateurs (1/7)
137
Riadh BEN HALIMA [Design patterns]
Le patron adapter :
Les adaptateurs dans l’OO (2/7)
Notre Classe du
système vendeur
existant
138
Riadh BEN HALIMA [Design patterns]
Le patron adapter :
Dinde et Canard (3/7)
Supposant que le dinde marche et cancane comme le canard
Un canard peut cancaner et voler Une simple implémentation du comportement du canard
140
Riadh BEN HALIMA [Design patterns]
Le patron adapter :
Testons l’adaptateur(5/7)
public class TestAdapter{
public static void main (String arg[])
{
Duck mallard= new MallardDuck();
Turkey wild = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(wild);
Duck tab[] = new Duck[2];
tab[0] = mallard;
tab[1] = turkeyAdapter ;
for(int i =0; i<2;i++)
{
tab[i].quack();
tab[i].fly();
}
}
}
Donner le résultat d’exécution de cette classe
141
Riadh BEN HALIMA [Design patterns]
Le patron adapter (6/7)
Définition: Adapter
Le patron Adapter convertit l’interface d’une classe à
une autre interface que le client attend. Les adaptateurs
permettent aux classes, aillant des interfaces incompatibles,
de travailler ensemble.
142
Riadh BEN HALIMA [Design patterns]
Adapter :
Le diagramme de classes du patron (7/7)
<<interface>>
Client Target
request() L’Adapter implémente
l’interface Target
143
Riadh BEN HALIMA [Design patterns]
Le patron
"Command"
144
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Spécification (1/28)
Objectif: Mettre en œuvre un système de contrôle distant
d’un ensemble d’appareils dans une maison
Besoin: programmer les fonctionnalités d’un contrôleur
distant (avec 7 slots) selon des classes (prédéfinies par le
vendeur) de gestion des appareils installés dans la maison.
Conception: OO
Prévoir les relations entre les boutons du contrôleur distant
(ON-OFF) avec les fonctionnalités des appareils installés:
setTemperature(), setVolume(), setDirection(), etc..
145
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Analyse du contrôleur distant (2/28)
146
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Les classes du vendeur (3/28)
Les classes du vendeur nous donnent une idée sur les fonctionnalités
des appareils installés dans la maison :
Faucet AirConditioner
Stereo Appliance
openValue() setTemperature()
on() on()
off() closeValue()
off()
setCD()
Security
setRadio()
setVolume() Light GarageDoor arm()
on() up() desarm()
off() down()
stop()
GardenLight lightOn() OutDoorLight
CeilingLight lightOff() on()
setDuskTime()
setDawnTime() on() off()
manualOn() off()
dim() Sprinkler
manualOff()
waterOn()
waterOff()
147
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Discussion de la conception (4/28)
On s’attendait à des classes avec des méthodes on()-off()
pour bien correspondre avec le contrôleur distant
C’est important de voir ça comme séparation des
préoccupation : le contrôleur doit savoir comment
interpréter l’appui sur le bouton et créer des requêtes, mais
il ne doit pas connaitre beaucoup sur les appareils et leurs
manières de fonctionnement (comment allumer une lampe)
En d’autre terme, le contrôleur émet des requêtes génériques
Une entité prendra en charge la transformation de cette requête
en action
148
Riadh BEN HALIMA [Design patterns]
Command :
Commander un dîner (5/28)
Order
Le client donne sa
commande à la serveuse
Customer Waitress
La serveuse récupère la
commande et la met sur le
comptoir, et la lance
Le cuisinier prépare le
repas selon la commande
Order-Cook
149
Riadh BEN HALIMA [Design patterns]
Command :
Etudes des interactions (6/28) Je veux
un burger,
un shake et
createOrder() des frites
Il y a toutes les
instructions
nécessaires pour takeOrder()
préparer le repas
La serveuse récupère la
orderUp()
commande et la met sur le
comptoir, et la lance
Le cuisinier suit
makeBurger(), makeShake(), makeShips()
les instructions
de la commande
output()
150
Riadh BEN HALIMA [Design patterns]
Command :
Les rôles et les responsabilités (7/28)
La commande (papier) est une requête pour préparer le repas
S’il s’agit d’un objet, il peut être passé de la serveuse au comptoir
Son interface consiste à une seule méthode orderUp(), qui encapsule les actions
nécessaires pour préparer le repas
La serveuse n’a besoin de savoir comment préparer le repas!
La tâche de la serveuse est de prendre la commande et d’invoquer
la méthode orderUp() dessus
La méthode takeOrder() de la serveuse peut être paramétrée avec différentes
commandes de plusieurs clients. Ceci ne la dérange pas car elle sait que orderUp()
supporte sa commande
Le cuisinier possède les connaissances nécessaires pour préparer le
repas
Suite à l’invocation de orderUp(), le cuisinier implémente toutes les méthodes
nécessaires pour créer le repas
Noter qu’il est complètement découplé de la serveuse
La serveuse encapsule les détails du repas dans la commande
Le cuisinier prend ses instructions de la commande, et il n’a pas besoin de la contacter
151
Riadh BEN HALIMA [Design patterns]
Command :
Du dîner vers le patron Commande (8/28)
Le client crée la commande.
public void execute(){ action1() La commande consiste à un
L’objet Command offre une receiver.action1(); action2()
ensemble d’actions et un receveur
…..
seule méthode execute() receiver.action2();
}
qui encapsule les actions create
createCommandObject( ) Command
Object
execute()
setCommand()
Plus tard, le client
demande à l’invoker
setCommand()
d’exécuter sa commande
execute()
execute()
de ceci résulte
action1(), action2() action1() l’invocation des
L’invoker appelle la méthode action2() actions sur le
execute() de l’objet Command ….. Receiver
152
Riadh BEN HALIMA [Design patterns]
Command :
Correspondance (9/28)
Dîner Command Pattern
Serveuse Command
(Waitress)
Cuisinier execute()
(Order-Cook)
orderUp() Client
Commande invoke
(Order)
Client Receiver
(Customer)
takeOrder() setCommand()
153
Riadh BEN HALIMA [Design patterns]
Command :
Le patron Command (10/28)
Définition: Command
Le patron Command encapsule une requête comme un
objet, ainsi il nous permet de paramétrer d’autres objets
avec différentes requêtes, files d’attentes ou longues
requêtes, et supporte l’annulation d’une opération
154
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Des Commandes (11/28)
Une requête encapsulée
action() execute()
execute()
execute(){
receiver.action()
}
execute() execute()
155
Riadh BEN HALIMA [Design patterns]
Command :
Le diagramme de classes du patron (12/28)
L’invoker tient la commande et Interface de tous les commandes.
Le client est responsable de
à un certain moment demande La commande est invoquée à travers
créer une ConcretCommand
à la commande de réaliser une sa méthode exécute, qui demande
et affecter son Receiver
requête en exécutant sa au Receiver de réaliser des actions
méthode execute()
Client <<interface>>
Invoker
Command
setCommand()
execute()
buttonWasPressed()
Receiver ConcretCommand
action() execute()
public SimpleRemoteControl() {}
158
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Notre premier objet Commande (15/28)
Testons la fonctionnalité du contrôleur distant
}
}
159
Riadh BEN HALIMA [Design patterns]
Home-Automation :
2ème Commande (16/28)
Développer la classe GarageDoorOpenCommand
GarageDoor
up()
down()
stop()
lightOn()
lightOff()
161
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Le contrôleur distant (18/28)
execute()
execute()
Light
Garage
Door execute()
Stereo
execute()
execute()
execute()
Le client <<interface>>
RemoteControl
Command
onCommands execute()
offCommands
RemoteLoader
setCommand()
onButtonWasPressed()
offButtonWasPressed()
Light LightOnCommand
on() execute()
off()
LightOffCommand
execute() public void execute(){
light.on();
public void execute(){
}
163 light.off();
} Riadh BEN HALIMA [Design patterns]
Home-Automation :
Programmer le contrôleur distant (20/28)
public class RemoteControl{
private Command onCommands[];
private Command offCommands[];
public RemoteControl() {
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand(); Eviter la gestion de null
for(int i=0;i<7;i++){
onCommands[i] = noCommand;
offCommands[i] = noCommand;
} }
public void setCommand(int slot, Command onCommand,Command offCommand ){
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
public void onButtonWasPressed(int slot){
onCommands[slot].execute();
}
public void offButtonWasPressed(int slot){
offCommands[slot].execute();
}
@Override
public String toString(){
String s="";
for(int i=0;i<7;i++){
s+="Slot["+i+"] "+onCommands[i].getClass().getName() +"
"+offCommands[i].getClass().getName()+"\n";
} return s;
}} 164
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Programmer les commandes (21/28)
Programmer les classes suivantes:
Light.java, Stereo.java
LightOnCommand,.java LightOffCommand.java,
StereoOnWithCDCommand.java, StereoOffCommand.java
public class LightOnCommand public class StereoOnWithCDCommand
implements Command { implements Command {
private Light light; private Stereo stereo;
public LightOnCommand(Light public StereoOnWithCDCommand(Stereo
light){ stereo){
this.light = light; this.stereo = stereo;
} }
@Override @Override
public void execute(){ public void execute(){
light.on(); stereo.on();
} stereo.setCD();
} stereo.setVolume(11);
}
}
165
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Tester le contrôleur (22/28)
public class RemoteLoader{
public static void main(String arg[]){
RemoteControl remoteControl = new RemoteControl();
Light livingRoomLight=new Light();
LightOnCommand livingRoomLightOnCommand = new
LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOffCommand = new
LightOffCommand(livingRoomLight);
remoteControl.setCommand(0, livingRoomLightOnCommand,livingRoomLightOffCommand);
remoteControl.onButtonWasPressed(0);
remoteControl.offButtonWasPressed(0);
Stereo stereo = new Stereo();
StereoOnWithCDCommand stereoOnWithCDCommand = new
StereoOnWithCDCommand(stereo);
StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo);
remoteControl.setCommand(1,stereoOnWithCDCommand,stereoOffCommand);
remoteControl.onButtonWasPressed(1);
remoteControl.offButtonWasPressed(1);
System.out.println(remoteControl.toString());
}
}
166
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Undo: Annuler la dernière opération (23/28)
Implémentons l’interface Command
public interface Command{
void execute();
void undo();
}
Implémentons une Commande pour allumer la lumière
public class LightOnCommand implements Command { Light
private Light light;
on()
public LightOnCommand(Light light){
off()
this.light = light;
}
@Override
public void execute(){
light.on();
} Opération à exécuter en cas
@Override d’annulation de cette commande
public void undo(){
light.off();
}
167 }
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Undo: Annuler la dernière opération (24/28)
public class RemoteControl{
private Command onCommands[];
private Command offCommands[];
private Command undoCommand; C’est ou on stockera la dernière
public RemoteControl() { commande exécutée pour le bouton undo
onCommands = new Command[7];
offCommands = new Command[7];
Command noCommand = new NoCommand();
for(int i=0;i<7;i++){
onCommands[i] = noCommand;
offCommands[i] = noCommand;
} Initialisation à NoCommand afin
undoCommand = noCommand; } d’éviter le traitement de null
public void onButtonWasPressed(int slot){
onCommands[slot].execute();
undoCommand = onCommands[slot];
}
public void offButtonWasPressed(int slot){ Enregistrer la dernière commande
offCommands[slot].execute();
undoCommand = offCommands[slot];
}
public void undoButtonWasPressed(){ Lorsqu’on appuie sur le bouton undo, on
undoCommand.undo(); invoque la méthode undo() pour annuler
} la dernière commande exécutée
} 168
Riadh BEN HALIMA [Design patterns]
Home-Automation :
Tester le contrôleur avec UNDO (25/28)
Annuler l’allumage de la lumière
class RemoteLoader{
public static void main(String arg[]){
//…
remoteControl.onButtonWasPressed(0);
remoteControl.undoButtonWasPressed();
//…
remoteControl.onButtonWasPressed(1);
remoteControl.offButtonWasPressed(1);
System.out.println(remoteControl.toString());
}
}
169
Riadh BEN HALIMA [Design patterns]
Home-Automation :
La Macro-Commande (26/28)
C’est le regroupement de plusieurs commandes en une seule
public class MacroCommand implements Command {
private Command [] commands; Stocker les commandes
public MacroCommand (Command [] commands){ de la macro-commande
this.commands = commands;
}
Un boucle pour exécuter
@Override
toutes les commandes de la
public void execute(){
macro-commande
for (int i=0;i<commands.length;i++)
commands[i].execute();
}
}
Créer les commandes à mettre dans la macro-commande
LightOnCommand lightOnCommand = new LightOnCommand(light);
StereoOnWithCDCommand stereoOnWithCDCommand = new
StereoOnWithCDCommand(stereo);
TVOnCommand tvOnCommand = new TVOnCommand(tv);
Créer les commandes
//créer aussi les Off-Commandes
170
Riadh BEN HALIMA [Design patterns]
Home-Automation :
MacroCommand (27/28)
Créer les macro-commandes
171
Riadh BEN HALIMA [Design patterns]
Autre utilisation du patron Command :
Organiser les queues de requêtes (28/28)
Les commandes nous offrent une manière de execute()
paquetage les morceaux de calcul (computation).
Les calculs (commandes créées par des applications)
execute()
seront placés dans des queues (queue de jobs) pour
être exécutés. execute()
execute()
172
Riadh BEN HALIMA [Design patterns]
Récapitulatif (1/2)
Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage
Principes de l’OO
Encapsuler ce qui varie
Favoriser la composition sur l’héritage
Programmer pour des interfaces
Opter pour une conception faiblement couplée
Les classes doivent être ouvertes pour les extensions et fermées pour les
modifications
Dépendre des abstractions. Ne jamais dépendre de classes concrètes
Patron de l’OO
Strategy: définit une famille d’algorithmes interchangeables
Observer: définit une dépendance1-à-plusieurs entre objets.
Decorator: attache des responsabilités additionnelles à un objet dynamiquement.
Abstract Factory: offre une interface de création de familles d’objets
Factory Method: définit une interface de création des objets
Singleton: assure à une classe une seule instance
Command: encapsule une requête comme un objet
173
Riadh BEN HALIMA [Design patterns]
Récapitulatif (2/2)
Le patron Command découple un objet, faisant des requêtes, de l’objet
qui sait comment la réaliser
Un objet Command est au centre de ce découplage et encapsule le
Receiver avec une action (ou des actions)
L’Invoker exécute la requête d’un objet Command en appelant sa
méthode execute(), qui invoque les actions sur le Receiver
Le patron Command supporte l’annulation (undo) par l’implémentation
d’une méthode undo() -dans la commande- qui restore l’ancien état du
système (avant l’exécution de la méthode execute())
Les Macro-Commandes sont des simples extensions de Command qui
permettent linvocation de multiple commandes. Pareil, les macro-
commandes peuvent supporter les méthodes d’annulation (undo).
Le patron Command est utilisé aussi pour implémenter l’organisation
des requêtes (Jobs) et la gestion de la journalisation (logging)
174
Riadh BEN HALIMA [Design patterns]
Exercice 1 (1/2)
On vous demande de participer à la création d’un nouvel outil graphique. Cet
outil permettra de créer de manière intuitive des dessins avec un niveau de
complexité plus ou moins élevé. Les dessins pourront être composés d’un
ensemble de points, droites, arc de cercles ou autres formes simples telles que
des cercles ou des polygones. Cet outil sera similaire au programme appelé
«Paint» sous l’environnement Windows. La figure suivante présente un
diagramme de classes simplifié pour cette application :
176
Riadh BEN HALIMA [Design patterns]
Exercice 2
Le but de cet exercice est de tester la puissance du pattern Command. Pour ce
faire, nous disposons d’une calculatrice offrant les opérations arithmétiques de
base : +, -, /, * et racine carrée sur 2 réels et nous voulons transformer les
actions (des utilisateurs) de calculs sur cette calculatrice en des commandes.
1. Donne le digramme de classes décrivant cette transformation avec le pattern
Command.
2. Implanter ce diagramme tout en respectant le client suivant :
public class Client {
public static void main(String[] args) {
Calculatrice calculatrice =new Calculatrice(); Calculatrice
Command plusCommand =new PlusCommand(calculatrice, 1, 3);
+ plus(x: float, y: float): float
Command sousCommand =new SousCommand(calculatrice, 8, 12); + mult(x: float, y: float): float
Command divCommand=new DivCommand(calculatrice, 7, 4); + sous(x: float, y: float): float
Command multCommand=new MultCommand (calculatrice, 4, 5); + div(x: float, y: float): float
Command sqrtCommand=new SqrtCommand(calculatrice, 9); + sqrt(x: float): float
CalculatriceControl control =new CalculatriceControl();
control.setCommand(0, plusCommand); control.buttonPressed(0);
control.setCommand(1, sousCommand); control.buttonPressed(1);
control.setCommand(2, divCommand); control.buttonPressed(2);
control.setCommand(3, multCommand); control.buttonPressed(3);
control.setCommand(4, sqrtCommand); control.buttonPressed(4); } }
3. Implanter la macro commande qui permet de résoudre l’équation :
Command secondDegre = new MacroCommand(calculatrice, 4, 5, 1); //a = 4, b = 5 et c = 1
Avec :
177
Riadh BEN HALIMA [Design patterns]
Le patron
"Façade"
178
Riadh BEN HALIMA [Design patterns]
Le patron Facade:
Démarrer un home-cinéma (1/4)
Tuner Amplifier
tuner DVDPlayer
Démarrer le HC: amplifier dvdPlayer
on() amplifier
baisser la lumière off() ….
on()
on()
allumer l’écran setAm() off()
off()
setFM() play()
setCD()
démarrer l’ampli …
setDVD()
stop()
pause()
démarrer le DvDplayer …
…
le brancher avec l’mpli
Screen
jouer le DvD
up()
etc.. down()
Définition: Façade
Le patron Façade présente une interface unifiée pour un
ensemble de sous-interfaces dans un système. La façade
définit une interface de haut niveau qui rend facile
l’utilisation du système.
181
Riadh BEN HALIMA [Design patterns]
Façade:
Le diagramme de classes du patron (4/4)
Une interface unifiée et
simple à utiliser
Client Façade
Systèmes complexes
182
Riadh BEN HALIMA [Design patterns]
Testons nos connaissances!
Patron Rôle
183
Riadh BEN HALIMA [Design patterns]
Le patron
"Builder"
184
Riadh BEN HALIMA [Design patterns]
Builder :
Définition: Builder
Le patron Builder (Monteur en français) sépare la
construction d'un objet complexe de sa représentation de
telle sorte que le même processus de construction peut
avoir différentes représentations.
185
Riadh BEN HALIMA [Design patterns]
Builder Construit un objet utilisant
la méthode du Builder
(builder.buildView())
Director Builder
builder : Builder
buildView() Classe abstraite qui
construct() contient le produit
186
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: préparer 2 configurations de voitures à vendre:
Couleur Rouge avec 4 roues && Couleur Noire avec 3 roues
CarDirector CarBuilder
builder : CarBuilder
buildView()
construct() getResult(): Car
car.setColor("Red");
car.setWheels(4); car.setColor("Black");
car.setWheels(3);
187
Riadh BEN HALIMA [Design patterns]
Builder vs autre patterns
Builder vs Factory
Factory : création d’un seul objet parmi plusieurs
Builder : création de plusieurs « objet » (ou objet
complexe ) par une seule méthode
Builder vs Decorator
Avec le Decorator, il est difficile de gérer tous les objets
créés et de les décorer
Avec le Builder, les combinaisons de « décoration » sont
pré-préparées
S’inspirant du service du restaurant:
A la carte : Builder
Self-Service : Decorator
188
Riadh BEN HALIMA [Design patterns]
Le patron
"Iterator"
189
Riadh BEN HALIMA [Design patterns]
Iterator :
Définition: Iterator
Le patron Iterator est utilisé pour obtenir un moyen
d'accéder aux éléments d'une collection d'objets de
manière séquentielle sans qu'il soit nécessaire de
connaître sa représentation.
190
Riadh BEN HALIMA [Design patterns]
Iterator :
« interface »
Iterator
hasNext(): boolean
next(): Object
SpecificIterator
hasNext(): boolean
next(): Object
191
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: Parcours d’un tableau de chaines avec un itérateur
192
Riadh BEN HALIMA [Design patterns]
Le patron
"Composite"
193
Riadh BEN HALIMA [Design patterns]
Composite :
Définition: Composite
Le patron Composite permet de manipuler un
groupe d'objets de la même façon que s'il s'agissait
d'un seul objet. L’objet composite est constitué d'un
ou de plusieurs objets similaires.
194
Riadh BEN HALIMA [Design patterns]
Composite :
*
Component
operation()
add(Component)
//autres méthodes
operation() operation()
//autres méthodes add(Component) for each g in children
//autres méthodes g.operation();
195
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: Représenter le contenu d’un disque dur ou d’un arbre
196
Riadh BEN HALIMA [Design patterns]
Exercice : Articles à vendre. Design
pattern "composite".
Une société vend des articles de papeterie. On se limite aux articles suivants:
• Stylos décrits par une référence, un nom (par exemple "stylo noir B2"), une
marque, un prix unitaire et une couleur,
• ramettes de papier décrites par une référence, un nom, une marque, un prix
unitaire et le grammage du papier (par exemple, 80 g/m²).
De plus cette société peut vendre ces articles par lots. On suppose que les lots
sont composés d'un certain nombre d'un même type d'articles, par exemple un
lot de 10 stylos noirs B2 de la marque BIC. Un lot a une référence et une
marque (celle de l'article). Le nom du lot est déterminé par le nombre d'articles
dont il est composé ; par exemple "Lot de 10 stylo noir B2". Le prix du lot est
déterminé par le prix unitaire de l'article multiplié par le nombre d'articles,
auquel est enlevé un certain pourcentage qui dépend du lot. Par exemple, si un
lot de 10 stylos à 5 dinars a un pourcentage de réduction de 20 %, le prix du lot
sera de 5 x (100 - 20) / 100 = 4 dinars. Ecrivez des classes pour représenter les
différents articles et testez le tout dans un main.
197
Riadh BEN HALIMA [Design patterns]
Le patron
"Proxy"
198
Riadh BEN HALIMA [Design patterns]
Proxy :
Définition: Proxy
Le patron Proxy fournit un substitut ou un espace réservé
pour un autre objet pour contrôler l'accès ou supporter
la distribution.
Il permet de supporter les objets gourmant en
ressources, et qu’on ne veut pas instancier jusqu'à ce
qu'ils soient effectivement demandés par le client.
199
Riadh BEN HALIMA [Design patterns]
Proxy :
Component
request()
//autres méthodes
RealSubject Proxy
request() request()
//autres méthodes //autres méthodes If (realSubject == null){
realSubject = new RealSubject();
}
realSubject.request();
200
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: Un contrôle d’accès du cash via le proxy chèque
201
Riadh BEN HALIMA [Design patterns]
Le patron
"State"
202
Riadh BEN HALIMA [Design patterns]
State:
Définition: State
Le patron State cherche principalement à séparer un objet
de ses états/comportements en encapsulant ces derniers dans
des classes à part.
Ces états/comportement, qui sont généralement des
singletons, sont interchangeables pour refléter l’état de l’objet
203
Riadh BEN HALIMA [Design patterns]
State :
Context
<<interface>>
currentState : State State
goNext() goNext(context)
setCurrentState(state)
currentState.goNext(this);
context.setCurrentState(StateTwo);
204
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: Représenter les 2 états d’un distributeur : vente/chargement
205
Riadh BEN HALIMA [Design patterns]
Le patron
"Bridge"
206
Riadh BEN HALIMA [Design patterns]
Bridge:
Définition: Bridge
Le patron Bridge découple une abstraction de son
implémentation afin que les 2 varient indépendamment
Le patron Bridge est utile lorsque la classe et ce quelle fait,
varie couramment.
207
Riadh BEN HALIMA [Design patterns]
Bridge :
208
Riadh BEN HALIMA [Design patterns]
Exemple d’utilisation
Objectif: L’interrupteur fonctionne avec abstraction de la cible
209
Riadh BEN HALIMA [Design patterns]
Le Modèle-Vue-
Contrôleur
210
Riadh BEN HALIMA [Design patterns]
Architecture Modèle/Vue/Contrôleur
Le modèle MVC: destiné à répondre aux besoins des applications
interactives en séparant les problématiques liées aux différents
composants au sein de leur architecture respective.
Ce paradigme regroupe les fonctions en trois catégories :
un modèle (modèle de données),
une vue (présentation, interface utilisateur)
un contrôleur (logique de contrôle, gestion des événements, synchronisation)
211
Riadh BEN HALIMA [Design patterns]
Le Modèle
212
Riadh BEN HALIMA [Design patterns]
La Vue
213
Riadh BEN HALIMA [Design patterns]
Le Contrôleur
Le contrôleur prend en charge la gestion des événements de
synchronisation pour mettre à jour la vue ou le modèle
reçoit tous les événements de l'utilisateur et enclenche les actions à
effectuer
Si une action nécessite un changement des données, le contrôleur
demande la modification des données au modèle, et ce dernier notifie la
vue que les données ont changé pour qu'elle se mette à jour.
D'après le patron de conception observateur/observable, la vue
est un « observateur » du modèle qui est lui « observable »
Le contrôleur n'effectue aucun traitement, ne modifie aucune donnée.
Il analyse la requête du client et se contente d'appeler le modèle adéquat et de
renvoyer la vue correspondant à la demande.
214
Riadh BEN HALIMA [Design patterns]
Flux de traitement
lorsqu'un client envoie une requête à l'application :
la requête envoyée depuis la vue est analysée par le contrôleur (par
exemple un clic de souris pour lancer un traitement de données) ;
le contrôleur demande au modèle approprié d'effectuer les traitements et
notifie à la vue que la requête est traitée (via par exemple un callback) ;
la vue notifiée fait une requête au modèle pour se mettre à jour (par exemple
affiche le résultat du traitement via le modèle).
215
Riadh BEN HALIMA [Design patterns]
Architecture MVC ou 3-Tier
216
Riadh BEN HALIMA [Design patterns]
Bibliographie
Head First: Design Patterns
https://sourcemaking.com/design_patterns/
Reconnaissance :
Slim BenHammouda, Squeezer Software
Wajdi Louati, ENIS
217
Riadh BEN HALIMA [Design patterns]