Design Patterns
Design Patterns
P. Laroque
octobre 2009
1 Introduction
3 Composition de patterns
A quoi ça sert?
Sources
Principe du cours
S'inspire de [hfdp]
Problème initial
nager,
Canard cancaner,
afficher...
Mandarin
Colvert
<<create>> Mandarin()
<<create>> Colvert()
afficher() : void
afficher() : void
Le pattern Strategy
Base <<interface>>
Behaviour
doSomething() : void
doSomething() : void
<<realize>> <<realize>>
Class1 Class2
Behaviour1 Behaviour2
doSomething() : void doSomething() : void
Canards stratégiques
Canard
<<create>> Canard()
setComportementVol(fb : ComportementVol) : void
setComportementCancan(qb : ComportementCancan) : void
afficher() : void
effectuerVol() : void
effectuerCancan() : void
nager() : void
<<interface>>
ComportementCancan
cancaner() : void <<interface>>
ComportementVol
voler() : void
<<realize>>
<<realize>>
La classe Canard I
public Canard() {
}
La classe Canard II
La classe Mandarin
public Mandarin() {
comportementVol = new VolerAvecDesAiles();
comportementCancan = new Cancan();
}
Résumé
Le problème
conditions actuelles
statistiques
prévisions simples
DonneesMeteo
temperature : float
humidite : float
pression : float
<<create>> DonneesMeteo()
setMesures(temperature : float,humidite : float,pression : float) : void
getPression() : float
getTemperature() : float
getHumidite() : float
Première approche
Problèmes
on n'a pas encapsulé ce qui varie (la MàJ des achages); pourtant,
même prols...
Le pattern Observateur
Principe:
Les acteurs
<<realize>>
<<realize>>
addObserver(this) MyObserver
MySource
<<interface>>
Sujet
DonneesMeteo
<<create>> DonneesMeteo()
enregistrerObservateur(o : Observateur) : void
supprimerObservateur(o : Observateur) : void
notifierObservateurs() : void
actualiserMesures() : void
setMesures(temperature : float,humidite : float,pression : float) : void
getTemperature() : float
getHumidite() : float
getPression() : float
<<interface>>
Observateur
<<interface>>
actualiser(temperature : float,humidite : float,pression : float) : void
Affichage
afficher() : void
<<realize>>
<<realize>>
La classe DonneesMeteo I
public DonneesMeteo() {
observateurs = new ArrayList();
}
La classe DonneesMeteo II
[Link](i);
}
}
actualiserMesures();
}
Un exemple d'achage I
Un exemple d'achage II
Un petit test
AffichageConditions affichageCond =
new AffichageConditions(donneesMeteo);
AffichageStats affichageStat = new AffichageStats(donneesMeteo);
AffichagePrevisions affichagePrev = new AffichagePrevisions(donneesMete
Résumé
Remarques
Le problème
Première approche
Critique
...
La décoration
Le pattern Décorateur
Component
m1() : void component
m2() : void
ConcreteComponent Decorator
m1() : void m1() : void
m2() : void m2() : void
ConcreteDecorator1 ConcreteDecorator2
m1() : void m1() : void
m2() : void m2() : void
m1() {
doSomethingWith(component.m1());
}
Boisson
getDescription() : String
cout() : double
DecorateurIngredient
Deca Sumatra Espresso Colombia
<<create>> Espresso()
cout() : double
Comment ça marche?
1.10
Chantilly
Chocolat
prix()
java 0.90
1.25
Le contexte
Introduction au pattern
Idée générale:
Cas simple
SimpleTelecommande
<<create>> SimpleTelecommande()
setCommande(commande : Commande) : void
boutonPresse() : void
<<interface>>
Commande
executer() : void
PorteGarage
<<create>> PorteGarage()
monter() : void Lampe
baisser() : void
arreter() : void <<create>> Lampe()
allumerLumiere() : void marche() : void
eteindreLumiere() : void arret() : void
/Commande
créer (Recepteur)
setCommande (c)
execute()
execute()
action()
Exemple de commande
Exemple d'invocateur
Le pattern Commande
Invocateur <<interface>>
setCommande(c : Commande) : void Commande
executer() : void
annuler() : void
<<realize>>
Recepteur
MaCommande
action() : void
executer() : void
annuler() : void
creer(recepteur)
executer() {
[Link]();
Client
}
Application à la télécommande
Programme de test I
// 1 - Creation de l'invocateur
Telecommande teleCommande = new Telecommande();
Programme de test II
CommandeFermerPorteGarage porteGarageFermee =
new CommandeFermerPorteGarage(porteGarage);
CommandeAllumerStereoAvecCD stereoAvecCD =
new CommandeAllumerStereoAvecCD(stereo);
CommandeEteindreStereo stereoEteinte =
new CommandeEteindreStereo(stereo);
Programme de test IV
stereoEteinte);
[Link](teleCommande);
Annulation I
Annulation II
}
}
public TelecommandeAvecAnnul() {
commandesMarche = new Commande[7];
commandesArret = new Commande[7];
Annulation III
commandesArret[i] = pasDeCommande;
}
commandeAnnulation = pasDeCommande;
}
Annulation IV
Le problème
Adaptateur OO:
Adaptateur
Canards et dindons
<<interface>> <<interface>>
Canard Dindon
cancaner() : void glouglouter() : void
voler() : void voler() : void
<<realize>> <<realize>>
Colvert DindonSauvage
Solution:
TestCanard
<<interface>>
<<interface>>
Dindon
Canard
glouglouter() : void
cancaner() : void
voler() : void
voler() : void
<<realize>> <<realize>>
<<realize>>
AdaptateurDindon DindonSauvage
Colvert
dindon : Dindon
Exemple de code
Le pattern Adaptateur
Client <<interface>>
Cible
requete() {
requete() : void [Link]fique();
}
<<realize>>
Adaptateur Adapté
requete() : void requeteSpecifique() : void
Le contexte
Les algorithmes
4 Ajouter du citron
void suivreRecette() {
faireBouillirEau();
filtrerCafe();
verserDansTasse();
ajouterLaitEtSucre();
}
Analyse supercielle
BoissonAInfuser
suivreRecette() : void
faireBouillirEau() : void
verserDansTasse() : void
The Cafe
suivreRecette() : void suivreRecette() : void
tremperSachet() : void filtrerCafe() : void
ajouterCitron() : void ajouterLaitSucre() : void
Etape suivante
portions de suivreRecette
2 préparer la boisson
3 verser la boisson
BoissonCafeinee
suivreRecette() : void
preparer() : void
ajouterSupplements() : void
faireBouillirEau() : void
verserDansTasse() : void
Cafe The
templateMethod() calls
variable operations
AbstractAlgorithm
templateMethod() : void
variableOp1() : void
variableOp2() : void
ConcreteAlgo1 ConcreteAlgo2
variableOp1() : void variableOp1() : void
variableOp2() : void variableOp2() : void
Principe de Hollywood
Le contexte
Plat
nom : String
description : String
vegetarien : boolean
prix : double
Hétérogène et redondant
Le pattern iterator
l'itérateur peut tester s'il reste des éléments non vus et passer à
l'élément suivant
<<interface>> <<interface>>
Collection Iterator
setIterator(i : Iterator) : void atEnd() : boolean
getIterator() : Iterator next() : Object
<<realize>> <<realize>>
<<realize>> <<realize>>
Test de l'itérateur I
[Link]("MENU\n----\nBRUNCH'");
P. Laroque (U.C.P.) Design patterns octobre 2009 77 / 129
catalogue Itérateur et Composite (iterator, composite)
Test de l'itérateur II
afficherMenu(iterateurCrepe);
[Link]("\nDEJEUNER");
afficherMenu(iterateurCafet);
}
[Link]("\nMENU VEGETARIEN\n----\nBRUNCH");
afficherMenuVegetarien([Link]());
[Link]("\nDEJEUNER");
afficherMenuVegetarien([Link]());
}
Test de l'itérateur IV
return false;
}
Test de l'itérateur V
Critique
Il faut donc que Plat et Menu aient un ancêtre commun dans l'arbre
d'héritage: pattern Composite
Le pattern Composite
0..*
<<interface>>
Element elements
operation() : void
add(e : Element) : void
remove(e : Element) : void
<<realize>> <<realize>>
LeafElement CompositeElement
operation() : void operation() : void
add(e : Element) : void
remove(e : Element) : void
Application au restaurant
ComposantDeMenu
ajouter(composantDeMenu : ComposantDeMenu) : void
remove(composantDeMenu : ComposantDeMenu) : void
getEnfant(i : int) : ComposantDeMenu IterateurComposite
IterateurNull getNom() : String 0..*
getDescription() : String
elements
getPrix() : double
estVegetarien() : boolean
creerIterateur() : Iterator
afficher() : void
Menu
Plat
<<create>> Menu(nom : String,description : String)
<<create>> Plat(nom : String,description : String,vegetarien : boolean,prix : double)
ajouter(composantDeMenu : ComposantDeMenu) : void
getNom() : String
remove(composantDeMenu : ComposantDeMenu) : void
getDescription() : String
getEnfant(i : int) : ComposantDeMenu
getPrix() : double
getNom() : String
estVegetarien() : boolean
getDescription() : String
creerIterateur() : Iterator
creerIterateur() : Iterator
afficher() : void
afficher() : void
ComposantDeMenu tousMenus =
new Menu("TOUS LES MENUS", "Toutes nos offres");
[Link](menuCreperie);
[Link](menuCafeteria);
[Link](menuBrasserie);
[Link]
(new Plat(
"Crepe a l'oeuf",
"Crepe avec oeuf au plat ou brouille",
true,
2.99));
[Link]
(new Plat(
"Crepe complete",
"Crepe avec oeuf au plat et jambon",
false,
2.99));
[Link]
(new Plat(
"Crepe forestiere",
"Myrtilles fraiches et sirop de myrtille",
true,
3.49));
P. Laroque (U.C.P.) Design patterns octobre 2009 90 / 129
catalogue Itérateur et Composite (iterator, composite)
[Link]
(new Plat(
"Crepe du chef",
"Creme fraiche et fruits rouges au choix",
true,
3.59));
[Link]
(new Plat(
"Salade printaniere",
"Salade verte, tomates, concombre, olives, pommes de terre"
true,
2.99));
[Link]
(new Plat(
"Salade Parisienne",
"Salade verte, tomates, poulet, emmental",
false,
2.99));
P. Laroque (U.C.P.) Design patterns octobre 2009 91 / 129
catalogue Itérateur et Composite (iterator, composite)
[Link]
(new Plat(
"Soupe du jour",
"Soupe du jour et croutons grilles",
true,
3.29));
[Link]
(new Plat(
"Quiche aux fruits de mer",
"Pate brisee, crevettes, moules, champignons",
false,
3.05));
[Link]
(new Plat(
"Quiche aux epinards",
"Pate feuilletee, pommes de terre, epinards, creme fraiche"
true,
3.99));
[Link]
P. Laroque (U.C.P.) Design patterns octobre 2009 92 / 129
catalogue Itérateur et Composite (iterator, composite)
(new Plat(
"Pasta al pesto",
"Spaghetti, ail, basilic, parmesan",
true,
3.89));
[Link](menuDesserts);
[Link]
(new Plat(
"Tarte du chef",
"Tarte aux pommes et boule de glace a la vanille",
true,
1.59));
[Link]
(new Plat(
"Charlotte maison",
"Charlotte aux poires et sauce au chocolat",
true,
P. Laroque (U.C.P.) Design patterns octobre 2009 93 / 129
catalogue Itérateur et Composite (iterator, composite)
1.99));
[Link]
(new Plat(
"Duos de sorbets",
"Une boule fraise et une boule citron vert",
true,
1.89));
[Link]
(new Plat(
"Omelette sarladaise",
"Omelette aux champignons et pommes sautees",
true,
3.99));
[Link]
(new Plat(
"Soupe de poissons",
"Soupe de poissons, rouille et croutons",
false,
P. Laroque (U.C.P.) Design patterns octobre 2009 94 / 129
catalogue Itérateur et Composite (iterator, composite)
3.69));
[Link]
(new Plat(
"Tagliatelles Primavera",
"Pates fraiches, brocoli, petits pois, creme fraiche",
true,
4.29));
[Link]();
}
}
Le contexte
Un distributeur de bonbons:
recharger
Première analyse
Critique
Par exemple, un bonbon gratuit avec une chance sur 10:
Solution possible
1 Réier la notion d'état dans une interface (qui contient une méthode
pour chaque action du distributeur)
Le pattern State
<<interface>>
DynamicObject
State
state
request() : void
handleRequest() : void
<<realize>>
<<realize>>
request() {
[Link]();
ConcreteState1 ConcreteState2
}
handleRequest() : void handleRequest() : void
Le distributeur revu
<<interface>>
Etat
Distributeur
insererPiece() : void
ejecterPiece() : void
tournerPoignee() : void
delivrer() : void
<<realize>>
Le distributeur I
Etat etatEpuise;
Etat etatSansPiece;
Etat etatAPiece;
Etat etatVendu;
Le distributeur II
[Link] = nombreBonbons;
if (nombreBonbons > 0) {
etat = etatSansPiece;
}
}
Le distributeur III
void liberer() {
[Link]("Un bonbon va sortir...");
if (nombre != 0) {
nombre = nombre - 1;
}
Le distributeur IV
int getNombre() {
return nombre;
}
Le distributeur V
Le distributeur VI
L'état gagnant I
L'état gagnant II
}
}
Le distributeur modié I
Etat etatEpuise;
Etat etatSansPiece;
Etat etatAPiece;
Etat etatVendu;
Etat etatGagnant;
Le distributeur modié II
[Link] = nombreBonbons;
if (nombreBonbons > 0) {
etat = etatSansPiece;
}
}
void liberer() {
[Link]("Un bonbon va sortir...");
if (nombre != 0) {
nombre = nombre - 1;
}
}
int getNombre() {
return nombre;
}
Le distributeur modié IV
Le distributeur modié V
return etatVendu;
}
Le distributeur modié VI
Remarques
(synchronisation)
Références
e
UML et les design patterns, C. Larman, 2 édition, CampusPress,
2003.