0% ont trouvé ce document utile (0 vote)
193 vues118 pages

Design Patterns

Transféré par

Larbi Bensalah
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
193 vues118 pages

Design Patterns

Transféré par

Larbi Bensalah
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Design patterns

Eléments de conception réutilisables

P. Laroque

octobre 2009

P. Laroque (U.C.P.) Design patterns octobre 2009 1 / 129


Outline

1 Introduction

2 Quelques Patterns Importants


Stratégie (strategy)
Observateur (observer)
Décorateur (decorator)
Commande (command)
Adaptateur (adapter)
Template de méthode (method template)
Itérateur et Composite (iterator, composite)
Etat (state)
Singleton
Fabrique (factory)
Méthode de fabrique (factory method)
Fabrique abstraite (abstract factory)

3 Composition de patterns

P. Laroque (U.C.P.) Design patterns octobre 2009 2 / 129


Introduction

Qu'est-ce que c'est?

algorithme au niveau de la conception

schéma susamment général pour être appliqué dans plusieurs


situations proches

morceau récurrent d'architecture logicielle

P. Laroque (U.C.P.) Design patterns octobre 2009 3 / 129


Introduction

A quoi ça sert?

Permet à un concepteur débutant d'éviter des écueils bien connus

Facilite la maintenance de l'application à concevoir

P. Laroque (U.C.P.) Design patterns octobre 2009 4 / 129


Introduction

Sources

1970's: C. Alexander, en architecture

1994: E. Gamma [Gamma], catalogue de patterns: la bible, complet


mais pas de processus

2003: C. Larman [Larman], processus (proche analyse) mais peu de


patterns

2004: E. Freeman [hfdp], approche pédagogique mais incomplet

P. Laroque (U.C.P.) Design patterns octobre 2009 5 / 129


Introduction

Principe du cours

S'inspire de [hfdp]

Sélection de patterns en situation

Groupement de plusieurs patterns sur une étude de cas

Code applicatif en Java

P. Laroque (U.C.P.) Design patterns octobre 2009 6 / 129


catalogue Stratégie (strategy)

Problème initial

Une application de jeu de simulation sur les canards

Les canards nagent et crient:

nager,
Canard cancaner,
afficher...

Mandarin
Colvert
<<create>> Mandarin()
<<create>> Colvert()
afficher() : void
afficher() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 8 / 129


catalogue Stratégie (strategy)

Faire voler les canards?

Simple: ajout d'une méthode voler() dans Canard ...

... Problème: les canards en plastique ne volent pas!

Solution: redénir voler() dans CanardEnPlastique ?

Non: le problème se pose dans d'autres classes (le canard lambda ne


vole pas non plus)

Il faut penser à séparer ce qui varie de ce qui demeure constant

On va essayer d'encapsuler les parties variables hors du code stable

P. Laroque (U.C.P.) Design patterns octobre 2009 9 / 129


catalogue Stratégie (strategy)

Le pattern Strategy

Base <<interface>>
Behaviour
doSomething() : void
doSomething() : void

<<realize>> <<realize>>
Class1 Class2
Behaviour1 Behaviour2
doSomething() : void doSomething() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 10 / 129


catalogue Stratégie (strategy)

Canards stratégiques

Canard
<<create>> Canard()
setComportementVol(fb : ComportementVol) : void
setComportementCancan(qb : ComportementCancan) : void
afficher() : void
effectuerVol() : void
effectuerCancan() : void
nager() : void

Mandarin PrototypeCanard CanardEnPlastique Colvert Leurre

<<interface>>
ComportementCancan
cancaner() : void <<interface>>
ComportementVol
voler() : void
<<realize>>
<<realize>>

Cancan FauxCancan Coincoin CancanMuet PropulsionAReaction NePasVoler VolerAvecDesAiles

P. Laroque (U.C.P.) Design patterns octobre 2009 11 / 129


catalogue Stratégie (strategy)

La classe Canard I

public abstract class Canard {


ComportementVol comportementVol;
ComportementCancan comportementCancan;

public Canard() {
}

public void setComportementVol (ComportementVol fb) {


comportementVol = fb;
}

public void setComportementCancan(ComportementCancan qb) {


comportementCancan = qb;
}

abstract void afficher();

public void effectuerVol() {


[Link]();
}

P. Laroque (U.C.P.) Design patterns octobre 2009 12 / 129


catalogue Stratégie (strategy)

La classe Canard II

public void effectuerCancan() {


[Link]();
}

public void nager() {


[Link]("Tous les canards flottent, même les leurres!");
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 13 / 129


catalogue Stratégie (strategy)

La classe Mandarin

public class Mandarin extends Canard {

public Mandarin() {
comportementVol = new VolerAvecDesAiles();
comportementCancan = new Cancan();
}

public void afficher() {


[Link]("Je suis un vrai mandarin");
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 14 / 129


catalogue Stratégie (strategy)

Résumé

Program to an interface: les behaviours

Chaque variation de comportement est une implémentation de


l'interface

Chaque classe qui a ce comportement référence une instance de (une


classe dérivée de) la behaviour: changement dynamique possible de
comportement!

Ajout de nouveaux comportements: indolore

P. Laroque (U.C.P.) Design patterns octobre 2009 15 / 129


catalogue Observateur (observer)

Le problème

Créer une interface pour station météo (température, hygrométrie,


pression)

Achage en temps réel à partir de données provenant de la station


des (un des trois)

conditions actuelles
statistiques
prévisions simples

P. Laroque (U.C.P.) Design patterns octobre 2009 17 / 129


catalogue Observateur (observer)

Les données d'entrée

DonneesMeteo
temperature : float
humidite : float
pression : float

<<create>> DonneesMeteo()
setMesures(temperature : float,humidite : float,pression : float) : void
getPression() : float
getTemperature() : float
getHumidite() : float

La méthode setMesures() est appelée périodiquement

Trois achages à réaliser initialement: à l'avenir, des ajouts / retraits


peuvent survenir et de nouveaux achages être créés

P. Laroque (U.C.P.) Design patterns octobre 2009 18 / 129


catalogue Observateur (observer)

Première approche

On écrit notre version de setMesures():


public void setMesures() {
float temp = getTemperature();
float humid = getHumidite();
float press = getPression();
[Link](temp, humid, press);
[Link](temp, humid, press);
[Link](temp, humid, press);
}

Problèmes

codage d'implémentations: statique (autres achages -> modication


de setMesures)

on n'a pas encapsulé ce qui varie (la MàJ des achages); pourtant,
même prols...

P. Laroque (U.C.P.) Design patterns octobre 2009 19 / 129


catalogue Observateur (observer)

Le pattern Observateur

1 Vous faites votre choix parmi les revues de l'OFUP

2 Vous vous abonnez à votre revue préférée et recevez les exemplaires


lors de leur parution

3 Vous arrêtez votre abonnement: vous ne recevez plus de revue

Principe:

un objet source (ou sujet) est observé par plusieurs objets


abonnés (intéressés par ses variations)

quand la source change d'état, tous les abonnés sont prévenus

chaque abonné réagit alors de la façon qui lui est propre

P. Laroque (U.C.P.) Design patterns octobre 2009 20 / 129


catalogue Observateur (observer)

Les acteurs

<<interface>> 0..* <<interface>>


Source Observer
source observers
addObserver(o : Observer) : void update() : void
removeObserver(o : Observer) : void
notify() : void

<<realize>>

<<realize>>
addObserver(this) MyObserver

MySource

P. Laroque (U.C.P.) Design patterns octobre 2009 21 / 129


catalogue Observateur (observer)

Application à la station météo

<<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>>

AffichagePrevisions AffichageStats AffichageHumidex AffichageConditions

P. Laroque (U.C.P.) Design patterns octobre 2009 22 / 129


catalogue Observateur (observer)

La classe DonneesMeteo I

public class DonneesMeteo implements Sujet {


private ArrayList observateurs;
private float temperature;
private float humidite;
private float pression;

public DonneesMeteo() {
observateurs = new ArrayList();
}

public void enregistrerObservateur(Observateur o) {


[Link](o);
}

public void supprimerObservateur(Observateur o) {


int i = [Link](o);
if (i >= 0) {

P. Laroque (U.C.P.) Design patterns octobre 2009 23 / 129


catalogue Observateur (observer)

La classe DonneesMeteo II

[Link](i);
}
}

public void notifierObservateurs() {


for (int i = 0; i < [Link](); i++) {
Observateur observer = (Observateur)[Link](i);
[Link](temperature, humidite, pression);
}
}

public void actualiserMesures() {


notifierObservateurs();
}

public void setMesures(float temperature, float humidite, float pression)


[Link] = temperature;
[Link] = humidite;
[Link] = pression;
P. Laroque (U.C.P.) Design patterns octobre 2009 24 / 129
catalogue Observateur (observer)

La classe DonneesMeteo III

actualiserMesures();
}

// autres méthodes de DonneesMeteo

public float getTemperature() {


return temperature;
}

public float getHumidite() {


return humidite;
}

public float getPression() {


return pression;
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 25 / 129


catalogue Observateur (observer)

Un exemple d'achage I

public class AffichageConditions implements Observateur, Affichage {


private float temperature;
private float humidite;
private Sujet donneesMeteo;

public AffichageConditions(Sujet donneesMeteo) {


[Link] = donneesMeteo;
[Link](this);
}

public void actualiser(float temperature, float humidite, float pression)


[Link] = temperature;
[Link] = humidite;
afficher();
}

public void afficher() {

P. Laroque (U.C.P.) Design patterns octobre 2009 26 / 129


catalogue Observateur (observer)

Un exemple d'achage II

[Link]("Conditions actuelles: " + temperature


+ " degrés C et " + humidite + "% d'humidité");
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 27 / 129


catalogue Observateur (observer)

Un petit test

public class StationMeteo {

public static void main(String[] args) {


DonneesMeteo donneesMeteo = new DonneesMeteo();

AffichageConditions affichageCond =
new AffichageConditions(donneesMeteo);
AffichageStats affichageStat = new AffichageStats(donneesMeteo);
AffichagePrevisions affichagePrev = new AffichagePrevisions(donneesMete

[Link](26, 65, 1020);


[Link](28, 70, 1012);
[Link](22, 90, 1012);
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 28 / 129


catalogue Observateur (observer)

Résumé

On a découplé la station des types d'achages

On peut donc ajouter de nouveaux types sans modier le code existant

Remarques

le pattern existe déjà en Java ( voir [Link] )


il est abondamment utilisé dans le JDK, notamment dans l'AWT et
dans SWING

P. Laroque (U.C.P.) Design patterns octobre 2009 29 / 129


catalogue Décorateur (decorator)

Le problème

Starbuzz coee veut un système unié de facturation pour ses points


de vente

Les cafés proposés sont de plusieurs types, et admettent de


nombreuses options (lait, chantilly, chocolat, caramel,...) qui ont une
inuence sur le prix

→ risque d'explosion combinatoire des classes!

P. Laroque (U.C.P.) Design patterns octobre 2009 31 / 129


catalogue Décorateur (decorator)

Première approche

Des variables d'instance pour les ingrédients dans la classe de base

La méthode prix() tient alors compte des ingrédients présents

Les sous-classes invoquent la méthode de base puis font les


ajustements nécessaires

P. Laroque (U.C.P.) Design patterns octobre 2009 32 / 129


catalogue Décorateur (decorator)

Critique

L'ajout de nouveaux ingrédients modie la classe de base (et les


méthodes prix() des classes dérivées)

Tous les ingrédients ne sont pas nécessairement adaptés à toutes les


boissons (thé chantilly?)

...

Un principe important: open-closed principle (principe ouvert-fermé)

Les classes doivent être ouvertes à l'extension, mais fermées à la


modication

P. Laroque (U.C.P.) Design patterns octobre 2009 33 / 129


catalogue Décorateur (decorator)

La décoration

Pour ne pas modier le code, on va le décorer avec du code


supplémentaire pour prendre en compte les nouvelles
informations /besoins

Par exemple, pour un expresso java avec chocolat et chantilly, on

prend l'expresso java


le décore avec un supplément chocolat
décore le résultat avec un supplément chantilly

La méthode prix() s'appuie sur la délégation

P. Laroque (U.C.P.) Design patterns octobre 2009 34 / 129


catalogue Décorateur (decorator)

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());
}

P. Laroque (U.C.P.) Design patterns octobre 2009 35 / 129


catalogue Décorateur (decorator)

Les boissons Starbuzz

Boisson
getDescription() : String
cout() : double

DecorateurIngredient
Deca Sumatra Espresso Colombia
<<create>> Espresso()
cout() : double

Lait Caramel Chantilly Chocolat


<<create>> Chocolat(boisson : Boisson)
getDescription() : String
cout() : double

P. Laroque (U.C.P.) Design patterns octobre 2009 36 / 129


catalogue Décorateur (decorator)

Comment ça marche?

public class Chocolat extends DecorateurIngredient {


Boisson boisson;

public Chocolat(Boisson boisson) {


[Link] = boisson;
}

public String getDescription() {


return [Link]() + ", Chocolat";
}

public double cout() {


return .20 + [Link]();
}
}
P. Laroque (U.C.P.) Design patterns octobre 2009 37 / 129
catalogue Décorateur (decorator)

Comment ça marche? (2)

1.10

Chantilly
Chocolat

prix()
java 0.90

1.25

P. Laroque (U.C.P.) Design patterns octobre 2009 38 / 129


catalogue Commande (command)

Le contexte

Un boitier programmable à 7 emplacements * 2 boutons (marche /


arrêt) + 1 annulation globale

Divers appareils ménagers à piloter (TV, plafonnier, porte garage,


Alarme, etc.)

Chaque appareil présente une interface d'utilisation particulière

Bien entendu, le boîtier decommande doit ignorer le détail du


fonctionnement des appareils

P. Laroque (U.C.P.) Design patterns octobre 2009 40 / 129


catalogue Commande (command)

Introduction au pattern

Analogie: le starbuzz coee. Déroulement des opérations:

1 Le CLIENT passe une COMMANDE au SERVEUR


il va créer une commande et la donner au serveur

2 le SERVEUR place la COMMANDE et demande au BARMAN de la


préparer
il peut ignorer le contenu de la commande!

3 le BARMAN prépare la COMMANDE


c'est le seul qui sait comment faire

Idée générale:

La commande, située entre le serveur et le barman, permet de les rendre


indépendants (découplage)

P. Laroque (U.C.P.) Design patterns octobre 2009 41 / 129


catalogue Commande (command)

Cas simple

SimpleTelecommande
<<create>> SimpleTelecommande()
setCommande(commande : Commande) : void
boutonPresse() : void

<<interface>>
Commande
executer() : void

CommandeOuvrirPorteGarage CommandeAllumerLampe CommandeEteindreLampe


<<create>> CommandeAllumerLampe(lampe : Lampe)
executer() : void

PorteGarage
<<create>> PorteGarage()
monter() : void Lampe
baisser() : void
arreter() : void <<create>> Lampe()
allumerLumiere() : void marche() : void
eteindreLumiere() : void arret() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 42 / 129


catalogue Commande (command)

Déroulement des opérations

/Client /Invocateur /Récepteur

/Commande
créer (Recepteur)

setCommande (c)

execute()
execute()
action()

P. Laroque (U.C.P.) Design patterns octobre 2009 43 / 129


catalogue Commande (command)

Exemple de commande

On suppose que le récepteur est une lampe, avec les méthodes


marche() et arret()

public class CommandeAllumerLampe implements Command {


Lampe lampe;
public CommandeAllumerLampe(Lampe lampe) {
[Link] = lampe;
}
public void executer() {
[Link]();
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 44 / 129


catalogue Commande (command)

Exemple d'invocateur

Une télécommande simple à un bouton

public class TelecommandeSimple {


Commande element1; // un seul, ici
public TelecommandeSimple() {}
public void setCommande (Commande c) {
element1 = c;
}
public void boutonPresse() {
[Link]();
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 45 / 129


catalogue Commande (command)

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
}

P. Laroque (U.C.P.) Design patterns octobre 2009 46 / 129


catalogue Commande (command)

Application à la télécommande

1 Création de l'invocateur (le boîtier)

2 Création des récepteurs

3 Création des objets Commande liés aux récepteurs

4 Aectation des commandes aux touches du boîtier de télécommande

5 Test d'appui sur les touches

P. Laroque (U.C.P.) Design patterns octobre 2009 47 / 129


catalogue Commande (command)

Programme de test I

public class ChargeurTelecommande {

public static void main(String[] args) {

// 1 - Creation de l'invocateur
Telecommande teleCommande = new Telecommande();

// 2 - creation des recepteurs


Lampe lampeSejour = new Lampe("Séjour");
Lampe lampeCuisine = new Lampe("Cuisine");
Ventilateur ventilateur= new Ventilateur("Séjour");
PorteGarage porteGarage = new PorteGarage("");
Stereo stereo = new Stereo("Séjour");

P. Laroque (U.C.P.) Design patterns octobre 2009 48 / 129


catalogue Commande (command)

Programme de test II

// 3 - Creation des objets "commande"


CommandeAllumerLampe lampeSejourAllumee =
new CommandeAllumerLampe(lampeSejour);
CommandeEteindreLampe lampeSejourEteinte =
new CommandeEteindreLampe(lampeSejour);
CommandeAllumerLampe lampeCuisineAllumee =
new CommandeAllumerLampe(lampeCuisine);
CommandeEteindreLampe lampeCuisineEteinte =
new CommandeEteindreLampe(lampeCuisine);
CommandeAllumerVentilateur ventilateurAllume =
new CommandeAllumerVentilateur(ventilateur);
CommandeEteindreVentilateur ventilateurEteint =
new CommandeEteindreVentilateur(ventilateur);
CommandeOuvrirPorteGarage porteGarageOuverte =
new CommandeOuvrirPorteGarage(porteGarage);

P. Laroque (U.C.P.) Design patterns octobre 2009 49 / 129


catalogue Commande (command)

Programme de test III

CommandeFermerPorteGarage porteGarageFermee =
new CommandeFermerPorteGarage(porteGarage);
CommandeAllumerStereoAvecCD stereoAvecCD =
new CommandeAllumerStereoAvecCD(stereo);
CommandeEteindreStereo stereoEteinte =
new CommandeEteindreStereo(stereo);

// 4 - affectation des commandes aux touches du boitier


[Link](0, lampeSejourAllumee,
lampeSejourEteinte);
[Link](1, lampeCuisineAllumee,
lampeCuisineEteinte);
[Link](2, ventilateurAllume,
ventilateurEteint);
[Link](3, stereoAvecCD,

P. Laroque (U.C.P.) Design patterns octobre 2009 50 / 129


catalogue Commande (command)

Programme de test IV

stereoEteinte);

[Link](teleCommande);

// 5 - test d'appui sur des touches


[Link](0);
[Link](0);
[Link](1);
[Link](1);
[Link](2);
[Link](2);
[Link](3);
[Link](3);
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 51 / 129


catalogue Commande (command)

Annulation I

Comment implémenter l'annulation générale?

Dénir une méthode annuler() dans l'interface Commande et


l'implémenter dans toutes les classes (ex. Lampe):

public class CommandeAllumerLampe implements Command {


Lampe lampe;
public CommandeAllumerLampe(Lampe lampe) {
[Link] = lampe;
}
public void executer() {
[Link]();
}
public void annuler() {
[Link]();

P. Laroque (U.C.P.) Design patterns octobre 2009 52 / 129


catalogue Commande (command)

Annulation II

}
}

Mémoriser la dernière commande exécutée dans le boîtier de


télécommande:

public class TelecommandeAvecAnnul {


Commande[] commandesMarche;
Commande[] commandesArret;
Commande commandeAnnulation;

public TelecommandeAvecAnnul() {
commandesMarche = new Commande[7];
commandesArret = new Commande[7];

Commande pasDeCommande = new PasDeCommande();


for(int i=0;i<7;i++) {
commandesMarche[i] = pasDeCommande;

P. Laroque (U.C.P.) Design patterns octobre 2009 53 / 129


catalogue Commande (command)

Annulation III

commandesArret[i] = pasDeCommande;
}
commandeAnnulation = pasDeCommande;
}

public void setCommande(int empt, Commande comMarche, Commande comArret)


commandesMarche[empt] = comMarche;
commandesArret[empt] = comArret;
}

public void boutonMarchePresse(int empt) {


commandesMarche[empt].executer();
commandeAnnulation = commandesMarche[empt];
}

public void boutonArretPresse(int empt) {


commandesArret[empt].executer();
commandeAnnulation = commandesArret[empt];
}
P. Laroque (U.C.P.) Design patterns octobre 2009 54 / 129
catalogue Commande (command)

Annulation IV

public void boutonAnnulPresse() {


[Link]();
}

public String toString() {


StringBuffer stringBuff = new StringBuffer();
[Link]("\n------ Télécommande -------\n");
for (int i = 0; i < [Link]; i++) {
[Link]("[empt " + i + "] "
+ commandesMarche[i].getClass().getName()
+ " "
+ commandesArret[i].getClass().getName() + "\n");
}
[Link]("[annulation] "
+ [Link]().getName() + "\n");
return [Link]();
}
}
P. Laroque (U.C.P.) Design patterns octobre 2009 55 / 129
catalogue Adaptateur (adapter)

Le problème

Adaptateur matériel: brancher un appareil électrique français aux US

Adaptateur OO:

Notre système Classe


existant propriétaire

Notre système Classe


existant propriétaire

Adaptateur

P. Laroque (U.C.P.) Design patterns octobre 2009 57 / 129


catalogue Adaptateur (adapter)

Canards et dindons

On veut ajouter des dindons à l'application canards:

<<interface>> <<interface>>
Canard Dindon
cancaner() : void glouglouter() : void
voler() : void voler() : void

<<realize>> <<realize>>

Colvert DindonSauvage

cancaner() : void glouglouter() : void


voler() : void voler() : void

Solution:

Créer un adaptateur de dindon vers canard!

P. Laroque (U.C.P.) Design patterns octobre 2009 58 / 129


catalogue Adaptateur (adapter)

L'adaptateur dindon vers canard

TestCanard

main(args : String[]) : void


testerCanard(canard : Canard) : void

<<interface>>
<<interface>>
Dindon
Canard
glouglouter() : void
cancaner() : void
voler() : void
voler() : void

<<realize>> <<realize>>
<<realize>>

AdaptateurDindon DindonSauvage
Colvert
dindon : Dindon

<<create>> AdaptateurDindon(dindon : Dindon) glouglouter() : void


cancaner() : void
cancaner() : void voler() : void
voler() : void
voler() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 59 / 129


catalogue Adaptateur (adapter)

Exemple de code

public class AdaptateurDindon implements Canard {


Dindon dindon;

public AdaptateurDindon(Dindon dindon) {


[Link] = dindon;
}

public void cancaner() {


[Link]();
}

public void voler() {


for(int i=0; i < 5; i++) {
[Link]();
}
}
P. Laroque (U.C.P.) Design patterns octobre 2009 60 / 129
catalogue Adaptateur (adapter)

Le pattern Adaptateur

But: convertir l'interface d'une classe en une autre compatible avec


l'application cliente.

Client <<interface>>
Cible
requete() {
requete() : void [Link]fique();
}

<<realize>>

Adaptateur Adapté
requete() : void requeteSpecifique() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 61 / 129


catalogue Template de méthode (method template)

Le contexte

On repère dans deux algorithmes de parties communes et des parties


spéciques

On va encapsuler les parties spéciques pour retenir un algorithme


global générique (algorithme à trou)

Illustration: le Starbuzz Coee, péparations du café et du thé

P. Laroque (U.C.P.) Design patterns octobre 2009 63 / 129


catalogue Template de méthode (method template)

Les algorithmes

Recette du café Recette du thé

1 Faire bouillir de l'eau 1 Faire bouillir de l'eau

2 Filtrer le café à l'eau bouillante 2 Faire infuser le thé dans l'eau

3 Verser le café dans une tasse bouillante

4 Ajouter du lait et du sucre


3 Verser le thé dans une tasse

4 Ajouter du citron

P. Laroque (U.C.P.) Design patterns octobre 2009 64 / 129


catalogue Template de méthode (method template)

Première version du code I

public class Cafe {

void suivreRecette() {
faireBouillirEau();
filtrerCafe();
verserDansTasse();
ajouterLaitEtSucre();
}

public void faireBouillirEau() {


[Link]("L'eau bout");
}

public void filtrerCafe() {


P. Laroque (U.C.P.) Design patterns octobre 2009 65 / 129
catalogue Template de méthode (method template)

Première version du code II

[Link]("Le café passe");


}

public void verserDansTasse() {


[Link]("Je verse dans la tasse");
}

public void ajouterLaitEtSucre() {


[Link]("Ajout de lait et de sucre");
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 66 / 129


catalogue Template de méthode (method template)

Analyse supercielle

Beaucoup de code commun avec The: héritage!

BoissonAInfuser
suivreRecette() : void
faireBouillirEau() : void
verserDansTasse() : void

The Cafe
suivreRecette() : void suivreRecette() : void
tremperSachet() : void filtrerCafe() : void
ajouterCitron() : void ajouterLaitSucre() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 67 / 129


catalogue Template de méthode (method template)

Etape suivante

On peut aller plus loin

les deux recettes utilisent le même algorithme −→ on va abstraire des

portions de suivreRecette

1 faire bouillir de l'eau

2 préparer la boisson

3 verser la boisson

4 ajouter des suppléments éventuels

P. Laroque (U.C.P.) Design patterns octobre 2009 68 / 129


catalogue Template de méthode (method template)

Etape suivante (code)

BoissonCafeinee
suivreRecette() : void
preparer() : void
ajouterSupplements() : void
faireBouillirEau() : void
verserDansTasse() : void

Cafe The

preparer() : void preparer() : void


ajouterSupplements() : void
ajouterSupplements() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 69 / 129


catalogue Template de méthode (method template)

Le pattern template de méthode

La classe abstraite contient l'algorithme (le template de méthode) et


des versions abstraites des éléments variables

Les éléments variables sont appelés dans l'algorithme

Chaque classe dérivée implémente sa version des éléments variables

P. Laroque (U.C.P.) Design patterns octobre 2009 70 / 129


catalogue Template de méthode (method template)

Le pattern (modèle UML)

templateMethod() calls
variable operations

AbstractAlgorithm
templateMethod() : void
variableOp1() : void
variableOp2() : void

ConcreteAlgo1 ConcreteAlgo2
variableOp1() : void variableOp1() : void
variableOp2() : void variableOp2() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 71 / 129


catalogue Template de méthode (method template)

Principe de Hollywood

Le composant de haut niveau AbstractAlgorithm invoque les


méthodes de ses sous-classes

Les sous-classes n'eectuent pas d'appel vers AbstractAlgorithm


C'est le principe de Hollywood: don't call us, we'll call you

Exemple: la fonction de comparaison dans qsort() (bibliothèque C)

P. Laroque (U.C.P.) Design patterns octobre 2009 72 / 129


catalogue Itérateur et Composite (iterator, composite)

Le contexte

Fusion de la cafeteria et de la crêperie

Deux menus distincts à gérer de manière homogène:

la cafeteria a une ArrayList de plats


la cêperie a un tableau de plats

Plat
nom : String
description : String
vegetarien : boolean
prix : double

<<create>> Plat(nom : String,description : String,vegetarien : boolean,prix : double)


getNom() : String
getDescription() : String
getPrix() : double
estVegetarien() : boolean
toString() : String

P. Laroque (U.C.P.) Design patterns octobre 2009 74 / 129


catalogue Itérateur et Composite (iterator, composite)

Problème: acher les plats

Hétérogène et redondant

Expose une connaissance de l'architecture interne

for (int i = 0; i < [Link](); i++)


Plat plat = (Plat)[Link](i);
...
}

for (int i = 0; i < [Link]; i++)


Plat plat = platsCreperie[i];
...
}

P. Laroque (U.C.P.) Design patterns octobre 2009 75 / 129


catalogue Itérateur et Composite (iterator, composite)

Le pattern iterator

chaque collection peut s'attacher un itérateur

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>>

MaCollection1 MaCollection2 MonIterateur1 MonIterateur2

P. Laroque (U.C.P.) Design patterns octobre 2009 76 / 129


catalogue Itérateur et Composite (iterator, composite)

Test de l'itérateur I

public class Serveuse {


Menu menuCreperie;
Menu menuCafeteria;

public Serveuse(Menu menuCreperie, Menu menuCafeteria) {


[Link] = menuCreperie;
[Link] = menuCafeteria;
}

public void afficherMenu() {


Iterator iterateurCrepe = [Link]();
Iterator iterateurCafet = [Link]();

[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);
}

private void afficherMenu(Iterator iterateur) {


while ([Link]()) {
Plat plat = (Plat)[Link]();
[Link]([Link]() + ", ");
[Link]([Link]() + " -- ");
[Link]([Link]());
}
}

public void afficherMenuVegetarien() {

P. Laroque (U.C.P.) Design patterns octobre 2009 78 / 129


catalogue Itérateur et Composite (iterator, composite)

Test de l'itérateur III

[Link]("\nMENU VEGETARIEN\n----\nBRUNCH");
afficherMenuVegetarien([Link]());
[Link]("\nDEJEUNER");
afficherMenuVegetarien([Link]());
}

public boolean estPlatVegetarien(String nom) {


Iterator iterateurCrepe = [Link]();
if (estVegetarien(nom, iterateurCrepe)) {
return true;
}
Iterator iterateurCafet = [Link]();
if (estVegetarien(nom, iterateurCafet)) {
return true;
}

P. Laroque (U.C.P.) Design patterns octobre 2009 79 / 129


catalogue Itérateur et Composite (iterator, composite)

Test de l'itérateur IV

return false;
}

private void afficherMenuVegetarien(Iterator iterateur) {


while ([Link]()) {
Plat plat = (Plat)[Link]();
if ([Link]()) {
[Link]([Link]());
[Link]("\t\t" + [Link]());
[Link]("\t" + [Link]());
}
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 80 / 129


catalogue Itérateur et Composite (iterator, composite)

Test de l'itérateur V

private boolean estVegetarien(String nom, Iterator iterateur)


while ([Link]()) {
Plat plat = (Plat)[Link]();
if ([Link]().equals(nom)) {
if ([Link]()) {
return true;
}
}
}
return false;
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 81 / 129


catalogue Itérateur et Composite (iterator, composite)

Critique

La serveuse traite toujours deux menus explicites et deux itérateurs

On va créer une interface commune, Menu (la Collection du pattern)


On pourra alors itérer une seule fois sur tous les menus

En outre, tout ajout d'un nouveau menu impose de retoucher le code


de la serveuse

regroupement possible des menus de la serveuse dans une collection:


on peut itérer sur cette collection!

P. Laroque (U.C.P.) Design patterns octobre 2009 82 / 129


catalogue Itérateur et Composite (iterator, composite)

Le code de la nouvelle serveuse I

public class Serveuse {


ArrayList menus;

public Serveuse(ArrayList menus) {


[Link] = menus;
}

public void afficherMenu() {


Iterator menuIterator = [Link]();
while([Link]()) {
Menu menu = (Menu)[Link]();
afficherMenu([Link]());
}
P. Laroque (U.C.P.) Design patterns octobre 2009 83 / 129
catalogue Itérateur et Composite (iterator, composite)

Le code de la nouvelle serveuse II

void afficherMenu(Iterator iterateur) {


while ([Link]()) {
Plat plat = (Plat)[Link]();
[Link]([Link]() + ", ");
[Link]([Link]() + " -- ");
[Link]([Link]());
}
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 84 / 129


catalogue Itérateur et Composite (iterator, composite)

Gestion des sous-menus

On veut maintenant ajouter un sous-menu pour les desserts

Problème: un menu est une collection de plats, pas une collection de


menus!

Solution: décrire et utiliser une structure de menus hiérarchique


(arborescente), chaque n÷ud pouvant être un plat (feuille) ou un
menu (n÷ud interne)

Il faut donc que Plat et Menu aient un ancêtre commun dans l'arbre
d'héritage: pattern Composite

P. Laroque (U.C.P.) Design patterns octobre 2009 85 / 129


catalogue Itérateur et Composite (iterator, 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

P. Laroque (U.C.P.) Design patterns octobre 2009 86 / 129


catalogue Itérateur et Composite (iterator, composite)

Application au restaurant

On va regrouper Plat et Menu sous ElementDeMenu et appliquer le


pattern Composite (rq: [Link]() renvoie false):
<<interface>>
Iterator
<<realize>> <<realize>>

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

P. Laroque (U.C.P.) Design patterns octobre 2009 87 / 129


catalogue Itérateur et Composite (iterator, composite)

Code nal de la serveuse

public class Serveuse {


ComposantDeMenu tousMenus;

public Serveuse(ComposantDeMenu tousMenus) {


[Link] = tousMenus;
}

public void afficherMenu() {


[Link]();
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 88 / 129


catalogue Itérateur et Composite (iterator, composite)

Test du couple composite / iterateur I

public class TestMenu {


public static void main(String args[]) {
ComposantDeMenu menuCreperie =
new Menu("MENU CREPERIE", "Brunch");
ComposantDeMenu menuCafeteria =
new Menu("MENU CAFETERIA", "Dejeuner");
ComposantDeMenu menuBrasserie =
new Menu("MENU BRASSERIE", "Diner");
ComposantDeMenu menuDesserts =
new Menu("MENU DESSERT", "Rien que des desserts !");

ComposantDeMenu tousMenus =
new Menu("TOUS LES MENUS", "Toutes nos offres");

[Link](menuCreperie);
[Link](menuCafeteria);
[Link](menuBrasserie);

P. Laroque (U.C.P.) Design patterns octobre 2009 89 / 129


catalogue Itérateur et Composite (iterator, composite)

Test du couple composite / iterateur II

[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)

Test du couple composite / iterateur III

[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)

Test du couple composite / iterateur IV

[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)

Test du couple composite / iterateur V

(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)

Test du couple composite / iterateur VI

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)

Test du couple composite / iterateur VII

3.69));
[Link]
(new Plat(
"Tagliatelles Primavera",
"Pates fraiches, brocoli, petits pois, creme fraiche",
true,
4.29));

Serveuse serveuse = new Serveuse(tousMenus);

[Link]();
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 95 / 129


catalogue Etat (state)

Le contexte

Un distributeur de bonbons:
recharger

Pas de pièce delivrer bonbon [bonbons>0]


Plus de bonbons

éjecter pièce insérer pièce delivrer bonbon [bonbons=0]

Une pièce tourner poignée Bonbon vendu

P. Laroque (U.C.P.) Design patterns octobre 2009 97 / 129


catalogue Etat (state)

Première analyse

Représenter les états par une variable interne discrète

final static public int PAS_DE_PIECE = 0;


final static public int PLUS_DE_BONBONS = 1;
final static public int UNE_PIECE = 2;
final static public int BONBON_VENDU = 3;

P. Laroque (U.C.P.) Design patterns octobre 2009 98 / 129


catalogue Etat (state)

Première analyse (suite)

Tester l'état dans toutes les actions:

public void insererPiece() {


if (etat == UNE_PIECE) {
[Link]("Vous ne pouvez plus insérer de pièce s");
} else if (etat == PAS_DE_PIECE) {
etat = A_PIECE;
[Link]("Vous avez inséré une pièce");
} else if (etat == PLUS_DE_BONBONS) {
[Link]("Vous ne pouvez pas insérer de pièce, nous somm
} else if (etat == BONBON_VENDU) {
[Link]("Veuillez patienter, le bonbon va tomber");
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 99 / 129


catalogue Etat (state)

Critique

Explicitation nécessaire du traitement de chaque état dans chaque


méthode

Lourdeur du code (structures conditionnelles trop nombreuses)

Extension dicile du statechart puisque très intégré au code

Par exemple, un bonbon gratuit avec une chance sur 10:

ajout d'un état GAGNANT


modication du code de toutes les méthodes du distributeur pour gérer
ce nouvel état

P. Laroque (U.C.P.) Design patterns octobre 2009 100 / 129


catalogue Etat (state)

Solution possible

1 Réier la notion d'état dans une interface (qui contient une méthode
pour chaque action du distributeur)

2 Implémenter cette interface dans une classe pour chaque état du


distributeur

3 Remplacer les conditionnelles par une délégation vers la bonne classe


état

P. Laroque (U.C.P.) Design patterns octobre 2009 101 / 129


catalogue Etat (state)

Le pattern State

<<interface>>
DynamicObject
State
state
request() : void
handleRequest() : void

<<realize>>
<<realize>>
request() {
[Link]();
ConcreteState1 ConcreteState2
}
handleRequest() : void handleRequest() : void

P. Laroque (U.C.P.) Design patterns octobre 2009 102 / 129


catalogue Etat (state)

Le distributeur revu

<<interface>>
Etat
Distributeur
insererPiece() : void
ejecterPiece() : void
tournerPoignee() : void
delivrer() : void

<<realize>>

EtatEpuise EtatSansPiece EtatVendu EtatAPiece

Le distributeur possède les méthodes setEtat() et getEtat() pour la


gestion des transitions

P. Laroque (U.C.P.) Design patterns octobre 2009 103 / 129


catalogue Etat (state)

Implémentation d'un état I

public class EtatSansPiece implements Etat {


Distributeur distributeur;

public EtatSansPiece(Distributeur distributeur) {


[Link] = distributeur;
}

public void insererPiece() {


[Link]("Vous avez inséré une pièce");
[Link]([Link]());
}

public void ejecterPiece() {


[Link]("Vous n'avez pas inséré de pièce");
P. Laroque (U.C.P.) Design patterns octobre 2009 104 / 129
catalogue Etat (state)

Implémentation d'un état II

public void tournerPoignee() {


[Link]("Vous avez tourné, mais il n'y a pas de
}

public void delivrer() {


[Link]("Il faut payer d'abord");
}

public String toString() {


return "attend une pièce";
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 105 / 129


catalogue Etat (state)

Le distributeur I

public class Distributeur {

Etat etatEpuise;
Etat etatSansPiece;
Etat etatAPiece;
Etat etatVendu;

Etat etat = etatEpuise;


int nombre = 0;

public Distributeur(int nombreBonbons) {


etatEpuise = new EtatEpuise(this);
etatSansPiece = new EtatSansPiece(this);
etatAPiece = new EtatAPiece(this);
P. Laroque (U.C.P.) Design patterns octobre 2009 106 / 129
catalogue Etat (state)

Le distributeur II

etatVendu = new EtatVendu(this);

[Link] = nombreBonbons;
if (nombreBonbons > 0) {
etat = etatSansPiece;
}
}

public void insererPiece() {


[Link]();
}

public void ejecterPiece() {


[Link]();
}

P. Laroque (U.C.P.) Design patterns octobre 2009 107 / 129


catalogue Etat (state)

Le distributeur III

public void tournerPoignee() {


[Link]();
[Link]();
}

void setEtat(Etat etat) {


[Link] = etat;
}

void liberer() {
[Link]("Un bonbon va sortir...");
if (nombre != 0) {
nombre = nombre - 1;
}

P. Laroque (U.C.P.) Design patterns octobre 2009 108 / 129


catalogue Etat (state)

Le distributeur IV

int getNombre() {
return nombre;
}

void refill(int nombre) {


[Link] = nombre;
etat = etatSansPiece;
}

public Etat getEtat() {


return etat;
}

P. Laroque (U.C.P.) Design patterns octobre 2009 109 / 129


catalogue Etat (state)

Le distributeur V

public Etat getEtatEpuise() {


return etatEpuise;
}

public Etat getEtatSansPiece() {


return etatSansPiece;
}

public Etat getEtatAPiece() {


return etatAPiece;
}

public Etat getEtatVendu() {


return etatVendu;
}

P. Laroque (U.C.P.) Design patterns octobre 2009 110 / 129


catalogue Etat (state)

Le distributeur VI

public String toString() {


StringBuffer result = new StringBuffer();
[Link]("\nDistribon, SARL.");
[Link]("\nDistributeur compatible Java, modèle 2004"
[Link]("\nStock : " + nombre + " bonbon");
if (nombre != 1) {
[Link]("s");
}
[Link]("\n");
[Link]("L'appareil " + etat + "\n");
return [Link]();
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 111 / 129


catalogue Etat (state)

Ajouter un état gagnant

1 Dénir une nouvelle classe implémentant Etat: EtatGagnant


2 Ajouter ce nouvel état possible au distributeur

3 Gérer le hasard et la transition possible de EtatAPiece vers


EtatGagnant

P. Laroque (U.C.P.) Design patterns octobre 2009 112 / 129


catalogue Etat (state)

L'état gagnant I

public class EtatGagnant implements Etat {


Distributeur distributeur;

public EtatGagnant(Distributeur distributeur) {


[Link] = distributeur;
}

public void insererPiece() {


[Link]
("Patientez s'il vous plait, un bonbon est en train d'être délivré");
}

public void ejecterPiece() {


[Link]
("Patientez s'il vous plait, un bonbon est en train d'être délivré");
}

P. Laroque (U.C.P.) Design patterns octobre 2009 113 / 129


catalogue Etat (state)

L'état gagnant II

public void tournerPoignee() {


[Link]
("Tourner une nouvelle fois la poignée ne vous donnera pas un autre b
}

public void delivrer() {


[Link]
("VOUS AVEZ GAGNE ! Deux bonbons pour le prix d'un !");
[Link]();
if ([Link]() == 0) {
[Link]([Link]());
} else {
[Link]();
if ([Link]() > 0) {
[Link]([Link]());
} else {
[Link]("Aïe, plus de bonbons !");
[Link]([Link]());
}
P. Laroque (U.C.P.) Design patterns octobre 2009 114 / 129
catalogue Etat (state)

L'état gagnant III

}
}

public String toString() {


return "délivre deux bonbons pour le prix d'un, car vous avez gagné !";
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 115 / 129


catalogue Etat (state)

Le distributeur modié I

public class Distributeur {

Etat etatEpuise;
Etat etatSansPiece;
Etat etatAPiece;
Etat etatVendu;
Etat etatGagnant;

Etat etat = etatEpuise;


int nombre = 0;

public Distributeur(int nombreBonbons) {


etatEpuise = new EtatEpuise(this);
etatSansPiece = new EtatSansPiece(this);
etatAPiece = new EtatAPiece(this);
etatVendu = new EtatVendu(this);
etatGagnant = new EtatGagnant(this);

P. Laroque (U.C.P.) Design patterns octobre 2009 116 / 129


catalogue Etat (state)

Le distributeur modié II

[Link] = nombreBonbons;
if (nombreBonbons > 0) {
etat = etatSansPiece;
}
}

public void insererPiece() {


[Link]();
}

public void ejecterPiece() {


[Link]();
}

public void tournerPoignee() {


[Link]();
[Link]();
}
P. Laroque (U.C.P.) Design patterns octobre 2009 117 / 129
catalogue Etat (state)

Le distributeur modié III

void setEtat(Etat etat) {


[Link] = etat;
}

void liberer() {
[Link]("Un bonbon va sortir...");
if (nombre != 0) {
nombre = nombre - 1;
}
}

int getNombre() {
return nombre;
}

void remplir(int nombre) {


[Link] = nombre;
etat = etatSansPiece;
P. Laroque (U.C.P.) Design patterns octobre 2009 118 / 129
catalogue Etat (state)

Le distributeur modié IV

public Etat getEtat() {


return etat;
}

public Etat getEtatEpuise() {


return etatEpuise;
}

public Etat getEtatSansPiece() {


return etatSansPiece;
}

public Etat getEtatAPiece() {


return etatAPiece;
}

public Etat getEtatVendu() {


P. Laroque (U.C.P.) Design patterns octobre 2009 119 / 129
catalogue Etat (state)

Le distributeur modié V

return etatVendu;
}

public Etat getEtatGagnant() {


return etatGagnant;
}

public String toString() {


StringBuffer result = new StringBuffer();
[Link]("\nDistribon, SARL.");
[Link]("\nDistributeur compatible Java, modèle 2004");
[Link]("\nStock : " + nombre + " bonbon");
if (nombre != 1) {
[Link]("s");
}
[Link]("\n");
[Link]("L'appareil " + etat + "\n");
return [Link]();
}
P. Laroque (U.C.P.) Design patterns octobre 2009 120 / 129
catalogue Etat (state)

Le distributeur modié VI

P. Laroque (U.C.P.) Design patterns octobre 2009 121 / 129


catalogue Etat (state)

La transition depuis EtatApiece I

public class EtatAPiece implements Etat {


Random hasard = new Random([Link]());
Distributeur distributeur;

public EtatAPiece(Distributeur distributeur) {


[Link] = distributeur;
}

public void insererPiece() {


[Link]("Vous ne pouvez pas insérer d'autre pièce");
}

public void ejecterPiece() {


[Link]("Pièce retournée");
[Link]([Link]());
}

P. Laroque (U.C.P.) Design patterns octobre 2009 122 / 129


catalogue Etat (state)

La transition depuis EtatApiece II

public void tournerPoignee() {


[Link]("Vous avez tourné....");
int gagnant = [Link](10);
if ((gagnant == 0) && ([Link]() > 1)) {
[Link]([Link]());
} else {
[Link]([Link]());
}
}

public void delivrer() {


[Link]("Pas de bonbon délivré");
}

public String toString() {


return "attend que la poignée soit tournée";
}
}

P. Laroque (U.C.P.) Design patterns octobre 2009 123 / 129


catalogue Etat (state)

Remarques

Découplage entre les objets et le statechart

Le pattern est très proche de Stratégie (même structure UML)

Mais les deux diérent dans le propos

Stratégie aecte un comportement à chaque classe (même s'il peut


changer au cours du temps)
Etat ne donne à la classe que l'état initial, qui change
(obligatoirement) dans les actions

P. Laroque (U.C.P.) Design patterns octobre 2009 124 / 129


Références

solution maison, indiquer que ça pose des problèmes avec le multi-thread

P. Laroque (U.C.P.) Design patterns octobre 2009 129 / 129


Références

(synchronisation)

Références

Design Patterns - Catalogue de modèles de conceptions réutilisables,


[Link] [Link] [Link] [Link], Vuibert, Juillet 1999

e
UML et les design patterns, C. Larman, 2 édition, CampusPress,
2003.

Design patterns tête la première, E. & E. Freeman, K. Sierra, B.


Bates, O'Reilly, 2004.

P. Laroque (U.C.P.) Design patterns octobre 2009 129 / 129

Vous aimerez peut-être aussi