Vous êtes sur la page 1sur 47

Plan

 Historique & Motivation


 Le patron « Strategy »
 Le patron « Observer »
Les patrons de conception  Le patron « Decorator »
(Design patterns)  Le patron « Abstract Factory »
 Le patron « Singleton »
 Le patron « Command »
 Le patron « Adapter »
Riadh BEN HALIMA
riadh.benhalima@enis.rnu.tn
Wajdi LOUATI
wajdi.louati@gmail.com
 Le patron « Façade »

1 2

Historique Motivation
 Notion de « patron » d’abord apparue en architecture :  Pourquoi définir des patrons de conception
 l’architecture des bâtiments  Construire des systèmes plus extensibles, plus robustes au changement
 la conception des villes et de leur environnement  Capitaliser l’expérience collective des informaticiens
 L’architecte Christopher Alexander le définit comme suit:  Réutiliser les solutions qui ont fait leur preuve
 «Chaque modèle [patron] décrit un problème qui se manifeste constamment  Identifier les avantages/inconvénients/limites de ces solutions
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:
 Savoir quand les appliquer
The Timeless Way of Building, Oxford University Press 1979]
 Complémentaire avec les API
 Projeter la notion de patron à du logiciel : "design pattern"  Une API propose des solutions directement utilisables
 premiers patrons à partir de 1987 (partie de la thèse de Erich Gamma)
 Un patron explique comment structurer son application avec une API
 puis Richard Helm, John Vlissides et Ralph Johnson («Gang of Four, GoF»)
 premier catalogue en 1993 : Elements of Reusable Object-Oriented Software
 Patron de conception dans le cycle de développement
 Intervient en conception détaillée
 Vocabulaire:
 modèles de conception= patrons de conception= motifs de conception= design  Reste indépendant du langage d’implantation
patterns
3 4
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Intérêt et utilisation des patrons de
Définition conception
 Définition : "Un patron de conception (design pattern)  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
décrit une structure commune et répétitive de des applications
composants en interaction (la solution) qui résout un
problème de conception dans un contexte particulier
Les concepts de l’orienté objet tels que
 Au lieu de la réutilisation de code, on parle de la l’abstraction, l’héritage, et le polymorphisme ne
réutilisation de l’expérience avec les patrons te rendent pas un bon concepteur!
Un concepteur pense à créer une conception
 Un bon patron de conception : flexible qui est maintenable et fait face aux
 résout un problème changements

 correspond à une solution éprouvée


 favorise la réutilisabilité, l’extensibilité, etc.

5 6
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Ce qu’il ne faut pas attendre des patrons


de conception Trois sortes de patrons

 Une solution universelle prête à l’emploi


 Une bibliothèque de classes réutilisables
 L’automatisation totale de l’instanciation d’un
patron de conception
 La disparition du facteur humain

7 8
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck:
Conception (1/22)
 Objectif: développement d’un jeu de simulation d’un bassin
pour les canards
 Besoin: nager, cancaner, afficher, etc..
Le patron 
 Supporter une large variété de canards
Conception: OO
"Strategy"  Une supère classe Canard (Duck) dont tous les canards héritent
Duck
quack()
Abstract swim()
display()

Autres types de Ducks


MallardDuck RedHeadDuck

display() display()

9 10
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck :
SimUDuck : Innovation (2/22) Problèmes (3/22)
 Objectif: Innovation (pour impressionner et vendre +)  Besoin: Au moment de la démonstration du simulateur, on nous
demande de simuler des canards en caoutchouc
 Besoin: simuler le vol des canards!
 Conception: OO
 Conception: OO  Ajouter la classe RubberDuck qui hérite de la supère classe Duck
 Ajouter la méthode fly() à la supère classe

Duck Duck
! Le caoutchouc ne vole pas

quack() quack()
swim() swim()
Modification apportée fly() Hériter par tous les canards fly()
display() display()

Autres types de Ducks


MallardDuck RedHeadDuck MallardDuck RedHeadDuck RubberDuck

display()
display() display() display() display()
quack(){
Redéfinir à squeak 
}
11 12
? Le caoutchouc ne cancane pas
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck : SimUDuck :
Constat (4/22) Solution?? (5/22)
 Problème 1: Le canard en caoutchouc ne cancane pas!  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 quack() à squeak()
(résolu)  Solution: Redéfinir la méthode fly() de RubberDuck
RubberDuck
 Problème 2: Le canard en caoutchouc ne vole pas! display()
Toutefois, il hérite la méthode fly() de la supère classe quack(){ squeak }
fly(){
Duck! Redéfinir à rien 
}
 Constat:
 Ce que nous avons cru une utilisation formidable de l’héritage  Question: est ce que c’est résolu pour tous types de canards?
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!
13 14
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck : SimUDuck :
Un autre canard (6/22) Des interfaces? (7/X)
 Nouveau type de canard: Canard en bois  Hypothèse: On nous demande de mettre à jour SimUDuck tous les 6 mois: La
spécification demeure changeante
 Problèmes levés:
 Vérifier fly() et quack() pour chaque nouveau canard
 Ce canard ne cancane pas  Ré-écrire (si besoin) fly() et quack()
 Ce canard ne vole pas  Solution possible pour contourner le problème: les interfaces
 Solution: redéfinir (une autre fois) les méthodes quack() et fly() Interface
Duck
WoodenDuck
Flyable Quackable swim()
display()
quack(){ fly() quack() display()
Redéfinir à rien 
}
fly(){
Redéfinir à rien 
} MallardDuck RedHeadDuck RubberDuck WoodenDuck
 Inconvénients de l’utilisation de l’héritage display() display() display() display()
fly() fly() quack()
 Il est difficile de connaitre le comportement de tous les canards quack() quack()
 Un changement non-intentionnelle, affecte les autres canards
15
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
16 Que dites vous de cette conception ?
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck : SimUDuck :
Inconvénients (8/22) Moment de réflexion (9/22)
Duck
Flyable Quackable swim()
 Pas toutes les sous-classes qui ont besoin de voler (fly)
fly() quack() display() ou de cancaner (quack)
 L’héritage n’est pas la bonne solution
 Les interfaces Flyable et Quackable résolvent une
MallardDuck RedHeadDuck RubberDuck WoodenDuck partie du problème
display() display() display() display()
fly() fly() quack()  Détruit complètement la réutilisation du code pour ces
quack() quack() comportements
 Constat:  La maintenance et la mise à jour représentent un vrai calvaire
 Duplication de code: méthodes fly() et quack() dans les sous-classes  Supposant qu’il existe plus qu’une façon de voler
 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)  Maintenance plus difficile…
 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 +)
17 18
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck : SimUDuck :
Solution (10/22) Principe de conception (11/22)

 Solution:
 Design pattern : solution ultime, cheval blanc, sauveur… Règle 1: Identifier les aspects variables de mon
application et les séparer de ce qui reste invariant

 Trouvons une solution avec l’"ancienne-mode" et ce en C’estla base de tous les patrons de conception
applicant les bonnes principes de la conception OO Système plus flexible+peu de conséquences inattendues
 Concevoir une application, ou un besoin de Mise en œuvre
modification/changement peut être appliqué avec le
moindre possible d’impact sur le code existant Prendre la partie qui varie et l’encapsuler. De cette
façon, un changement ultérieur affecte la partie
Donner des raisons de changement de code
variable, sans toucher à celle invariable
dans votre application
19 20
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck : SimUDuck :
Séparation (12/22) Conception des comportements (13/22)
 La classe Duck est toujours la supère classe  Conception initiale: l’inflexibilité des comportements a engendré
des troubles
 Les comportements fly() et quack() sont retirés, et mis dans une
autre structure  On veut affecter les comportements aux instances des Ducks
tout en permettant:
Comportements  La création d’une instance (MallardDuck),
Mettre dehors ce qui varie  L’initialisation avec un type de comportement (type de vol)
 La possibilité de changer le type de vol dynamiquement (?)

Duck class Le comportement Fly


 Règle 2: Programmer des interfaces, et non des
Le comportement Quack implémentations
 Programmer pour les super-types!
 On utilise des interfaces pour représenter chaque
Invariable Variable comportement: FlyBehavior et QuackBehavior
21 22
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck : SimUDuck :
Conception des comportements (14/22) Intégration des comportements(15/22)
FlyBehavior QuackBehavior
fly() quack()
 La supère classe Duck, dont hérite tous les canards
Duck Variable d’instance
du type INTERFACE
FlyBehavior fbehavior;
FlyWithWings FlyNoWay Quack Squeak MuteQuack QuackBehavior qbehavior;
fly() { fly() { quack(){ quack(){ quack(){
//squeak //rien-ne performQuack()
//vol //rien-ne vol pas //quack
//rubber //cancane pas swim()
} } }
} } display()
performFly()
 Conséquences: //….
 On peut ajouter un nouveau comportement sans modifier ni le code des Ces méthodes remplacent quack() et fly()
comportements existants, ni le code des classes des canards qui utilisent les
comportements voler/cancaner  La clé: le canard délègue les comportements fly et quack,
 Avec cette conception, d’autres objets peuvent réutiliser le comportement fly et au lieu d’utiliser les méthodes fly() et quack() définies
quack, parce qu’ils ne sont plus cachés dans les classes canards.
dans la supère classe Duck.
23 24
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck : SimUDuck :
Implémentation de la supère classe(16/22) Implémentation d’un canard (17/22)
 La supère classe Duck, dont hérite tous les canards
Cette classe inclut les méthodes réalisant
le comportement fly et quack, par héritage
public class Duck{ (performQuack(), etc..)
QuackBehavior qbehavior; Chaque type de canard initialise ces attributs
FlyBehavior fbehavior; selon ses besoins.
//… (par FlyWithWings pour le MallardDuck )
public class MallardDuck extend Duck{
public void performQuack(){ public MallardDuck (){ Initialisation des attributs déclarés
qbehavior.quack(); fbehavior = new FlyWithWings(); dans la supère classe Duck
} qbehavior = new Quack();
//..
}
} Grace au polymorphisme, la bonne méthode sera public void display(){
invoquée dans la sous-classe du type de canard. System.out.println("Je suis un canard Mallard");
(Déléguée à la classe gérant le comportement) }
}

25 26
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck : SimUDuck :
Tester le code du canard(18/22) Le comportement dynamique (19/22)
 Développer et compiler [Utiliser NetBeans/Eclipse]:  Changement dynamique de comportement
 La classe abstraite Duck (Duck.java)  Ajouter les méthodes: setFlyBehavior() et setQuackBehavior()
 Le comportements: FlyBehavior.java, FlyWithWings.java et  Développer le canard RedHeadDuck (RedHeadDuck.java)
FlyNoWay.java,  Implanter le nouveau comportement "vole-force-fusée"
 Le comportement : QuackBehavior.java, Quack.java, Squeak.java et FlyRocketPowered (FlyRocketPowered.java)
MuteQuack.java
 Tester le nouveau canard dans un main RedHeadSim.java
 Les classes MallardDuck.java et WoodenDuck.java
 Changer le comportement "voler" de FlyWithWings à
 Tester toutes les méthodes des canards créés dans un main: FlyRocketPowered. Penser à utiliser le setter afin d’obtenir ces
MallardDuckSim.java deux affichages: "Je peux voler" & "Je vole comme une fusée"

 Donner (et ne pas implémenter) les modifications à faire afin


d’ajouter le comportement manger: eat()
27 28
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
SimUDuck : SimUDuck :
La conception finale (20/22) Composition/Héritage (21/22)
QuackBehavior
quack()  Has-a: liaison intéressante
Duck
QuackBehavior qbehavior;
 Chaque canard possède un FlyBehavior et QuackBehavior qui
FlyBehavior fbehavior; implements délègue flying et quacking
Quack Squeak MuteQuack
performQuack()  Composition (mettre les 2 classes ensemble)
swim() quack(){ quack(){ quack(){
display() //quack //squeak //rien-ne  Encapsuler une famille d’algorithmes dans leur propre ensemble
//rubber //cancane pas
performFly() }
} }
de classes
setFlyBehavior()
setQuackBehavior()  Remplacer l’héritage pour favoriser le changement dynamique du
\\autre méthodes FlyBehavior comportement
fly()
extends
MallardDuck WoodenDuck  Règle 3: Favoriser la composition sur l’héritage
implements
display(){ display(){
\\canard Mallard \\canard en bois FlyWithWings FlyNoWay
} } fly() { fly() {
//vole //ne vole pas
Algorithmes } }
29 30
interchangeables Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

SimUDuck :
Notre premier patron (22/22) Les avantages du patron

 Notre premier patron: STRATEGIE


 Si les algorithmes/comportements sont dans une classe a part,
Le patron stratégie cherche principalement à séparer il est beaucoup plus facile de:
un objet de ses comportements/algorithmes en  se retrouver dans le code principale
encapsulant ces derniers dans des classes à part.  enlever, ajouter et modifier un algorithme/comportement
 diminuer l’utilisation de tests conditionnels
Pour ce faire, on doit alors définir une famille de  éliminer la redondance et le couper/coller
 accroître la réutilisabilité du code ainsi que sa flexibilité
comportements ou d’algorithmes encapsulés et
interchangeables.

31 32
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
L’implémentation du patron Représentation du patron

 Pour implémenter le patron « Strategy » on doit:


 1. Définir une interface commune à tout les algorithmes ou
comportements de même famille.
 Ceci ce fait habituellement en créant une classe abstraite.

 2. Créer les classes comportant les algorithmes ou les


comportements à partir de l’interface commune.

 3. Utiliser la stratégie voulue dans le code de l’objet.

33 34
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Récapitulatif (1/2) Récapitulatif (2/2)


 Bases de l’OO:  Connaitre les bases de l’OO ne fait pas de toi un bon concepteur
 Les meilleurs conception OO sont réutilisable, flexible et
 Abstraction, Encapsulation, Polymorphisme & Héritage maintenable
 Principes de l’OO  Les patrons nous guident à construire des systèmes avec les bonnes
qualités de la conception OO
 Encapsuler ce qui varie
 Les patrons sont des expériences prouvées dans l’OO
 Favoriser la composition sur l’héritage  Les patrons ne donnent pas de code, mais plutôt des solutions
 Programmer avec des interfaces et non des implémentations générales pour des problèmes de conception
 Les patrons de sont pas inventés, mais découverts
 Patron de l’OO (stratégie)  La majorité des patrons et des principes adresses les problèmes de
 Le patron stratégie définit une famille d’algorithmes, les changement dans le logiciel
encapsule, et les rend interchangeable. Ce patron laisse  On essaie toujours de prendre ce qui varie des systèmes et on
l’encapsule
l’algorithme varier indépendamment du client qu’il l’utilise.
 Les patrons offrent un langage partagé qui peut maximiser la valeur
de la communication avec les autres développeurs

35 36
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Exercice (1/2) Exercice (2/2)
 Ci-dessous, on donne l’ensemble de classes et interfaces d’un jeu 1. Arranger les classes
d’action et d’aventure. Il y a des classes d’individus avec des
classes pour les comportements d’armes que les individus
2. Identifier les classes, les classes abstraites des interfaces
peuvent utiliser. Chaque individu peut utiliser une seule arme à la 3. Relier les entités pas des flèches ou:
fois, mais peut la changer à tout moment durant le jeu. La tâche 1. représente extends
demandée est d’ordonner le tout. 2. représente implements
Individu ComportementCouteau Chevalier 3. représente has-a
ComportementArme arme; UtiliseArme(){\\abattre avec Display(){….} 4. Mettre la méthode setArme() dans la classe
combattre() couteau }
Display () correspondante
Archer ComportementArc&Fleche
Reine
Display(){….} UtiliseArme(){\\abattre avec
5. Implémenter et tester cette conception dans un main.
Display(){….} arc et flèche} Penser à changer dynamiquement le comportement de
ComportementArme l’archer après avoir finir ces arcs.
setArme(ComportementArme ca) {
UtiliseArme();
this.arme=ca; ComportementEpee
}
UtiliseArme(){\\abattre avec
37 épée} 38
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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
Le patron

météorologique et les prévisions météo.
 Poursuivre les conditions météorologiques (Température,
"Observer" 
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.

39 40
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Station météo: Station météo:
Analyse (2/14) Conception (3/14)
WeatherData Ces trois méthodes retournent les
mesures les plus récentes
Afficher getTemperature()
Capteur getHumidity()
d’humidité Tirer (pull) Cette méthode sera appelée chaque
getPressure()
fois qu’on met à jour les mesures
measurementChanged()
Capteur de \\autre méthodes
température
Weather Station
WeatherData  Nous allons développer trois afficheurs:
Object
Capteur de Conditions  conditions courantes (CurrentConditionsDisplay.java)
pression courantes
 statistiques météorologique (StatisticsDisplay.java)
Le fournisseur ENIS-METEO A implémenter  prévisions météo (ForecastDisplay.java)
 Il faut créer une application qui utilise l’objet WeatherData afin de  Rq: On ne s’intéresse pas à la manière dont les variables sont fixées.
mettre à jour trois afficheurs: les conditions courantes, les statistiques On suppose que l’objet WeatherData connait comment les mettre à
météorologiques & les prévisions météo. jour à partie de la station ENIS-METEO
41 42
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Station météo: Station météo:


Une solution possible (4/14) Constat (5/14)
public class WeatherData  Problème : En codant des implémentations concrètes, on ne peut pas
Récupérer les mesures les
{ plus récentes
ajouter/supprimer d’autres afficheurs, sans faire un changement du
//attributs programme!
void setMeasurement(){  Rq: on peut au moins utiliser une interface qui contient la
float temperature = getTemperature(); méthode update().
float humidity = getHumidity()  Solution : le patron observer
float pressure = getPressure()
 Exemple:
currentConditionsDisplay. update(temperature, humidity, pressure); 1. Une maison d’édition commence l’édition d’un journal
statisticsDisplay. update(temperature, humidity, pressure); 2. Vous vous inscrivez à ce journal, et pour chaque nouvelle
forecastDisplay. update(temperature, humidity, pressure); édition, vous recevez votre copie
} 3. Vous vous désinscrivez lorsque vous ne voulez plus recevoir
//autres méthodes des journaux
}
Mettre à jour les afficheurs
4. Les gens, les hôtels etc. peuvent constamment s’inscrire et se
avec les nouvelles mesures désinscrire à ce journal.
43 44
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Station météo: Station météo:
Publier/Souscrire= Patron Observer (6/14) Patron Observer : S’inscrire (7/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

Les objets Observers

Les objets Observers

45 46
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Station météo: Station météo:


Patron Observer : Notification(8/14) Patron Observer : Désinscrire (9/14)
Maintenant, le Mouse est un
observer, il reçoit les
notifications du Sujet

Nouvel entier

Les objets Observers Les objets Observers

47 48
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Station météo: Station météo:
Patron Observer : Notification (10/14) Le patron Observer (11/14)
 Définition: Observer
Maintenant, le Dog n’est plus un
observer, il ne reçoit plus les
 Le patron observer définit une dépendance 1-à-plusieurs
notifications du Sujet 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.

12
1-à-plusieurs

Les objets dépendants


12 8

Nouvel entier
8

Les objets Observers


L’objet qui tient les mises
Mise à jour/notification
à jours Les objets Observers
automatique
49 50
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Station météo: Station météo:


Diagramme de classes du patron (12/14) La puissance du couplage faible (13/14)
Chaque Subject possède Tous les observers potentiels doivent
un tableau d’observers implémenter l’interface "Observer"
 Deux objets, qui sont faiblement couplés, entrent en interaction
Les objets utilisent avec très peu de connaissance de l’un envers l’autre.
cette interfaces pour <<interface>> observers <<interface>>
s’inscrire comme Subject Observer  Le patron Observer permet de réaliser une conception ou le
observer et aussi se
désinscrire registerObserver() Update() Subject et l’Observer sont faiblement couplés
removeObserver()
notifyObservers()  Couplage faible : plus d’indépendance et de flexibilité
 La seule chose que le Subject a besoin de connaitre sur l’Observer est
subject qu’il implémente une certaine interface.
ConcreteSubject ConcreteObserver
 On peut ajouter/remplacer/supprimer un observer à tout moment
Le ConcreteSubject registerObserver(){…} Update()
hérite toujours de
sans toucher au Subject
removeObserver() {…} //autres méthodes
l’interface Subject. Il
notifyObservers() {…}  On peut réutiliser le Subject ou l’Observer facilement parcequ’il ne
implémente la méthode
notifyObservers() qui sont pas fortement couplés.
est sensée mettre à getState()
jour l’observer quand setState()
Toutes classes qui implémente l’observer est  La modification du Subject ou de l’Observer n’affecte pas l’autre classe
l’état change.
un observer concret. Chaque observer  Règle 4: Opter pour une conception faiblement couplée
concret s’inscrit auprès d’un sujet concret
pour recevoir l’update entre les objets qui interagissent
51 52
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Station météo:
La conception finale (14/14) Le Patron Observateur
observers
<<interface>> <<interface>> <<interface>>
Subject Observer DisplayElement
registerObserver() update() display()
removeObserver()
notifyObservers()

CurrentConditionsDisplay
subject
WeathetData update()
display()
registerObserver(){…}
removeObserver() {…}
notifyObservers() {…}
StatisticsDisplay ForecastDisplay
getTemperature()
getHumidity() update() update()  Le patron de conception observateur/observable est utilisé pour envoyer
getPressure() display() display() un signal à des modules qui jouent le rôle d'observateur.
measurementChanged()  En cas de notification, les observateurs effectuent alors l'action adéquate en
fonction des informations qui parviennent depuis les modules qu'ils
Les trois afficheurs pointent sur le WeatherData afin
de permettre leur inscription et leur désinscription
observent (les "observables").
53 54
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Récapitulatif (1/2) Récapitulatif (2/2)


 Bases de l’OO:  Le patron observer définit une relation 1-à-plusieurs entre
 Abstraction, Encapsulation, Polymorphisme & Héritage objets.
 Principes de l’OO  Le Subject/Observable met à jour les observers à travers
 Encapsuler ce qui varie une interface commune.
 Favoriser la composition sur l’héritage
 L’observer est faiblement couplé avec le Subject. Ce
 Programmer avec des interfaces et non des implémentations
dernier ne connait rien d’eux à part qu’ils implémentent
 Opter pour une conception faiblement couplée entre les objets
l’interface Observer.
qui interagissent
 Patron de l’OO  On peut récupérer les données du Subject en mode
 Strategy: définit une famille d’algorithmes interchangeables
pull/push. (Le Subject fait le push, semble plus correct)
 Observer: définit une dépendance1-à-plusieurs entre objets, de  On ne dépend pas d’un ordre spécifique de notification
façon que pour chaque changement de l’état d’un objet , ses entre les observers
dépendants sont notifiés et mis à jour automatiquement.  Java possède plusieurs implémentations de ce patron
55 56
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Exercice Exercice (1/2)
1. Appliquer le patron Observer sur l’application station météo en se  Les méthodes getSecondes, getMinutes et getHeures permettent d’accéder aux
basant sur les implémentations du Subject et de l’Observer offertes valeurs des secondes, minutes et heures respectivement. La classe Chrono est une
classe concrète implantant l’interface de la classe AbstractChrono. Lorsqu’une
par Java : seconde passe (tick()), les Displays doivent afficher les heures, les minutes et les
 java.util.Observable : Subject du patron (Attention! Il s’agit d’une classe) secondes et les Sonneries doit faire entendre un tintement chaque heure.
 java.util.Observer : Observer du patron

Sonnerie1 AbstractChrono DisplayNumerique


<<interface>>
Pour dire Observable Observer int secondes;
explicitement que int minutes;
l’état de l’observable addObserver(Observer o) update(Observable o, Object ding() int heures; afficheTempsEcoule()
a changé. Elle ne fait deleteObserver(Observer o) arg) getSecondes()
pas la notification. notifyObservers(Object arg) getMinutes()
getHeures()
setChanged() Ou tick()
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)
Sonnerie2 Chrono DisplayAiguille
offertes sont déjà implémentées.

2. Expliquer comment Java utilise le patron observer pour la gestion ding()


afficheTempsEcoule()
des évènements sur les interfaces graphiques.
57 58
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Exercice (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.

 public static void main(String[] args) {


Chrono c=new Chrono();
Le patron
Sonnerie_Observer S1=new Sonnerie1(c);
Sonnerie_Observer S2=new Sonnerie2(c);
Display_Observer D1= new DisplayNumerique(c);
"Decorator"
Display_Observer D2= new DisplayAiguille(c);
for(int i=1;i<5000;i++)
{ try{Thread.sleep(1000);}
catch(InterruptedException e) {System.out.print("erreur");}
c.tick((i%3600)%60, (int)((i%3600)/60), (int)(i/3600)); } }

59 60
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
StarCoffee : StarCoffee :
Spécification (1/10) Conception (2/10)
 Objectif: Mettre en œuvre un système de gestion des offres Beverage Retourne la description
Description
de boisson pour la clientèle de StarCoffee Méthode abstraite à définir
dans les classes dérivées getDescription()
 Besoin: Décrire les ajouts en extra, et calculer le prix total cost()

 Thé, Thé-à-la-menthe, Thé-à-la-mente-aux-pignons, etc..


 Café, Café-au-Lait, Café-au-Lait-à-la-mousse, etc.. Tea
 Conception: OO Coffee
cost()
cost() CoffeeWithMilk
 Concevoir une supère classe Boisson que toutes les autres TeaWithMint
classes héritent. cost()
CoffeeWithMilk cost()
 Définir autant de classes qu’il y en a de types de boissons : WithWhip
TeaWithMintWit
cost() hPine
 Beverage.java, Coffee.java, CoffeeWithMilk.java,
cost()
CoffeeWithMilkWithWhip.java, Tea.java, TeaWithMint.java,
TeaWithMintWithPine.java, etc.
Chaque sous classe implémente la méthode
61 62
cost() qui représente le prix du boisson
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

StarCoffee : StarCoffee :
Problème (3/10) Nouvelle conception (4/10)
 Problème : En plus des deux produits présentés précédemment, Beverage
StarCoffee offre une variété d’autres boissons et condiments: (Si Description
Milk
on offre 2 types de Thé, on doit ajouter plusieurs autres classes Mint
(selon les condiments possibles), etc. Pine
Whip
 Constat: éclatement du diagramme de classes par un nombre ingérable getDescription()
cost()
de classes Beverage hasMilk()
Description
 Solution : Utiliser des variables Milk
setMilk()
Des booléans hasMint()
d’instance dans la supère classe qui Mint
Pine setMint()
Dans chaque classe dérivée,
représenteront les condiments Whip hasPine()
on ajoute les condiments
getDescription() setPine()
(pignon, mousse, lait, menthe). cost() hasWhip() (set), puis c’est la méthode
hasMilk() setWhip() cost() qui calcule le prix
setMilk() total (en vérifiant avec has)
hasMint()
Coffee Tea
setMint()
hasPine() cost() cost()
Des get et set pour les setPine()
booleans des condiments hasWhip()
63 64
setWhip LOUATI [Design patterns]
Riadh BEN HALIMA&Wajdi Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
StarCoffee : StarCoffee :
Un boisson décoré (5/10) Un boisson décoré (6/10)
1. On commence par l’objet Tea 3. Le client veut aussi des pignons, alors on crée un objet Pine qui
La classe Tea hérite de Beverage et possède une emballe le Mint L’objet Pine est un décorateur, donc il est un
cost() méthode cost() qui calcule le prix du boisson miroir du type Tea et inclut une méthode cost()

2. Le client choisit la menthe, alors on crée un objet Mint qui


cost() cost() cost()
enveloppe le Tea
L’objet Mint possède une méthode cost() et à travers
le polymorphisme, on peut traiter chaque Beverage
enveloppé dans le Mint comme un Beverage aussi.
cost() cost()
L’objet Tea, enveloppé dans un Mint et un Pine,
reste toujours un Beverage. Alors on peut faire
avec lui ce qu’on peut faire avec les Beverage, y
compris l’invocation de sa méthode cost()
L’objet Mint est un décorateur. Son type est un
miroir de l’objet qu’il décore (Beverage).
65 66
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

StarCoffee : StarCoffee :
Le coût du boisson décoré (7/10) Le patron Decorator (8/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.  Définition: Decorator
Pine appelle cost() de Mint  Le patron decorator attache des responsabilités
 Invocation de la méthode Mint appelle cost() de Tea additionnelles à un objet dynamiquement. Les décorateurs
cost() du décorateur extérieur offrent une alternative flexible de sous-classement afin
d’étendre les fonctionnalités.
cost() cost() cost()

0.300 0.200 0.500

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

67 68
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
StarCoffee : StarCoffee :
Le diagramme de classes du patron(9/10) La conception finale (10/10)
Chaque composant peut être utilisé à lui
seul, ou enveloppé dans des décorateurs Beverage
Component Beverage agit comme notre
classe abstraite component description
Component
methodA() getDescription()
methodB() Chaque décorateur possède un composant, qui veut cost();
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
//autres méthodes
dynamiquement des nouveaux
comportements. Il étend
l’objet Component.

ConcreteComponent Decorator Coffee Tea CondimentDecorator Le constructeur du


Les décorateurs implémentent cost() cost() décorateur prend le
la même interface (ou classe boisson à décorer en
methodA() methodA() getDescription();
abstraite) que l’objet qu’ils entrée et retourne le
methodB() methodB() décoreront
boisson décoré.
//autres méthodes //autres méthodes
Les deux composants
concrets, 1 par type de boisson

ConcreteDecoratorA ConcreteDecoratorB Whip Milk Mint Pine


Le ConcreteDecorator possède
un attribut qui représente l’objet Component WrappedObj Component WrappedObj Beverage beverage Beverage beverage Beverage beverage Beverage beverage
qu’il décore. Il peut ajouter ses Object newState
propres méthodes et attributs. methodA()
methodB() methodA() cost() cost() cost() cost()
Newbehavior() methodB()
69 70
//autres méthodes //autres méthodes
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Récapitulatif (1/2) Récapitulatif (2/2)


 Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage  L’héritage est une forme d’extension, mais il n’est pas nécessairement
 Principes de l’OO la meilleure manière pour obtenir la flexibilité dans notre conception
 Encapsuler ce qui varie
 Le patron decorator implique un ensemble de classes de décorations
 Favoriser la composition sur l’héritage
qui sont utilisées pour envelopper les composants concrets.
 Programmer avec des interfaces et non des implémentations
 Les classes décorateurs reflètent le type de composant qu’ils
 Opter pour une conception faiblement couplée
décorent.
 Les classes doivent être ouvertes pour les extensions et fermées pour
les modifications  Les décorateurs changent le comportement de leurs composants tout
 Patron de l’OO en ajoutant des nouvelles fonctionnalités après/avant (ou à la place de)
 Strategy: définit une famille d’algorithmes interchangeables l’appel des méthodes des composants
 Observer: définit une dépendance1-à-plusieurs entre objets.  On peut envelopper un composant dans n’importe quel nombre de
 decorator: attache des responsabilités additionnelles à un objet décorateurs
dynamiquement. Les décorateurs offrent une alternative flexible de sous-
 Les décorateurs sont transparents par rapport au client du
classement afin d’étendre les fonctionnalités.
composant
71 72
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Exercice (1/3) Exercice (2/3)
1. Comment faire pour obtenir un café avec "double mousse"?  Avec le patron decorator, le package java.io doit donner plus de
2. StarCoffee a ajouté un nouveau boisson (Citronnade) au système, sens, puisqu’il se base largement sur ce patron.
comment procéder pour l’inclure dans la conception actuelle?
FileInputStream est un composant
3. StarCoffee veut introduire des tailles pour ses menus: SMALL, décoré. Le package java.io offre plusieurs
objets pour la lecture des octets:
MEDIUM et LARGE. Comment prendre en charge cette nouvelle FileInputStream,
spécification, si la taille modifie seulement les prix des composants StringBufferInputStream,
concrets? ByteArrayInputStream, etc.

BufferedInputStream est un décorateur concret. Il


LineNumberInputStream est aussi ajoute deux comportements: (i) il tamponne les
un décorateur concret. Il ajoute la entrées afin d’améliorer la performance, et (ii)
capacité de compter les nombres ajoute la méthode readLine() pour lire une ligne de
de lignes en lisant les données. caractères à la fois.

73 74
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Exercice (3/3): Décoration de java.io


1. Ecrire un décorateur qui convertit tous les caractères majuscules  L’objectif de cet exercice est de mettre en œuvre un
en minuscules dans le flux d’entrée (InputStream). système flexible de gestion des offres de voiture pour la
Abstract Component
Conctrete clientèle de StarCar. Le besoin de cette société se résume à
Component InputStream
Abstract Decorator décrire les options demandées par le client (VitreElectrique,
AirBag et ABS) et inclure son cout au prix total de la
FileInputStream StringBufferInputStream FilterInputStream voiture choisie. Deux types de voiture sont gérés par la
société, à savoir, camionnette et berline. Chaque voiture est
ByteArrayInputStream 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.
PushBackInputStream BufferedInputStream  En utilisant le patron Decorator, donnez le diagramme de
Decorator classes de l’application CarStar. (Précisez les méthodes et
LineNumberInputStream
DataInputStream les attributs, correspondant au bout de code ci-dessous)
75 76
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
public static void main(String[] args) {
Voiture v1=new Camionnette ("P404",10000);
Voiture v2=new Berline ("P407",20000);

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

"Adapter"
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, AirBag
System.out.println("Son prix est:"+ v2.cost());
//affiche: Son prix est 22200

77 78
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Le patron adapter : Le patron adapter :


Les adaptateurs (1/7) Les adaptateurs dans l’OO (2/7)
Notre Classe du
système vendeur
existant

L’interface ne correspond par à ce qu’on a déjà codé.


Ça ne va pas marché!
Adaptateur Câble American du PC (supposant qu’on ne peut pas changer de vendeur)
Prise Européenne

Notre Adaptateur Classe du


système vendeur
L’adaptateur convertit une existant
interface à une autre

Même code Nouveau code Même code

79 80
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Le patron adapter : Le patron adapter :
Dinde et Canard (3/7) L’adaptateur du dinde(4/7)
 Supposant que le dinde marche et cancane comme le canard  Supposons qu’on a un manque de canards et on va utiliser des
Un canard peut cancaner et voler Une simple implémentation du comportement du canard
dindes à leur pace  Il faut écrire un "adapter"

class MallardDuck implements Duck{ Respecter l’interface des canards


interface Duck{
void quack(); public void quack(){
class TurkeyAdapter implements Duck{
void fly(); System.out.println("Quack");}
Turkey turkey;
} public void fly(){
TurkeyAdapter(Turkey turkey){
System.out.println("Fly");}
this.turkey=turkey;}
} Une référence vers l’objet à adapter
public void quack(){
interface Turkey{ Le dinde ne cancane pas, mais glougloute turkey.gobble();
void gobble(); }
void fly(); Le dinde peut voler (courte distance) Translation des méthodes
public void fly(){
}
for(int i=0;i<5;i++)
turkey.fly();
class WildTurkey implements Turkey{ }
public void gobble(){ }
System.out.println("Gobble");}
public void fly(){
System.out.println("Fly for a short distance");}
81 } 82
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Le patron adapter :
Testons l’adaptateur(5/7) Le patron adapter (6/7)

Adapter
public class TestAdapter{
public static voir main (String arg[])  Définition:
{
MallardDuck mallard= new MallardDuck();  Le patron Adapter convertit l’interface d’une classe à
WildTurkey wild = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(wild);
une autre interface que le client attend. Les adaptateurs
test(mallard); permettent aux classes, aillant des interfaces incompatibles,
de travailler ensemble.
test(turkeyAdapter);
}
static void test(Duck duck)
{
duck.quack();
duck.fly();
}
}

 Donner le résultat d’exécution de cette classe

83 84
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Adapter :
Le patron adapter (6/7)
Le diagramme de classes du patron (7/7)

<<interface>>
Client Target
Request() L’Adapter implémente
l’interface Target

Le client voit seulement


Adapter Adaptee
l’interface Target.
Request() specificRequest()

L’adapter est composé Toutes les requêtes sont


d’un Adaptee déléguées à Adaptee

85 86
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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() ….

Le patron
on()
on()
 allumer l’écran setAm() off()
off()
setFM() play()
setCD()
 démarrer l’ampli … stop()

"Façade"
setDVD()
pause()
 démarrer le DvDplayer …

le brancher avec l’mpli
Screen
jouer le DvD
up()
 etc.. down()

87 88 Et bien d’autres classes


Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Le patron Facade:
Les classes d’un Home cinéma (2/4) Le patron façade (3/4)
La Façade: une nouvelle Le client invoque les
classe pour le méthodes sur la Façade
WatchDVD()
HomeCinema avec peu
de méthode
HomeCinema
WatchTV()
 Définition: Façade
WatchDVD()
….
 Le patron Façade présente une interface unifiée pour un
ensemble de sous-interfaces dans un système. La façade
Amplifier
Tuner DVDPlayer
définit une interface de haut niveau qui rend facile
amplifier tuner amplifier
dvdPlayer l’utilisation du système.
on() …. on()
off() off() La classe Façade traite les
setAm() on() play() composants du
setFM() off() stop() HomeCinema comme des
… setCD() pause() sous-systèmes qu’il invoque
setDVD() …

pour implémenter ses
CDPlayer méthodes
amplifier Projector
on() Screen on()
off() off()
up()
play()
down()
stop()
pause()
89 90
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Façade:
Le diagramme de classes du patron (4/4) Testons nos connaissances!
Une interface unifiée et
simple à utiliser

Client Façade

Patron Rôle
Un client heureux car
son travail devient Decorator Convertit une interface en une
facile grâce à la façade Les classes des sous-systèmes
autre

Adapter Ne modifie pas l’interface,


mais ajoute des responsabilités

Systèmes complexes
Facade Rend les interfaces simples

91 92
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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
Le patron

 Il y a plusieurs objets dont on a besoin d’une seule instance:
pool d’impression, boite de dialogue, objet qui manipule les
"Singleton" 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.

93 94
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Singleton : Singleton :
Créer un singleton (2/12) Créer un singleton (3/12)
 Comment créer un seul objet?  Comment je peux appeler cette méthode (pour créer une
 New MonObjet()
instance) si je n’ai pas d’instance?
 Et si un autre objet veut créer un MonObjet? Est-ce qu’il peut  static
public class MonObjet{
appeler new sur MonObjet une autre fois?  Que signifie ce code. public static MonObjet getInstance() {
}
 Oui }
 Pour toute classe, est ce qu’on peut l’instancier plus qu’une fois?  C’est une méthode statique qui peut être appelée à partir du nom de la
 Oui (il faut que la classe soit publique) classe : MonObjet.getInstance()
 Que signifie ce code ?  Si on met les choses ensemble, est ce qu’on peut instancier
public class MonObjet{
 C’est une classe qui ne peut pas être instanciée, private MonObjet() {}
MonObjet? public class MonObjet{
car elle possède un constructeur privé } private MonObjet(){ }
public static MonObjet getInstance() {
return new MonObjet();
 Qui peut utiliser ce constructeur? }
 Le code de MonObjet est le seul code qui peut l’appeler (dans une méthode) }
 Comment faire pour créer une seule instance?
95 96
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Singleton : Singleton :
Implémentation du patron (4/12) L’usine de chocolat (5/12)
Nous avons une variable statique public class ChocolateBoiler{
pour stocker notre instance private boolean empty; Le code démarre lorsque
private boolean boiled; la casserole est vide
public class Singleton { public ChocolateBoiler() {
empty=true; boiled=false;
private static Singleton uniqueInstance; Pour remplir la casserole, elle
}
private Singleton() {} Le constructeur est déclaré privé. public void fill(){ doit être vide. Lorsqu’elle est
public static Singleton getInstance(){ Seulement la classe Singleton qui if (empty){ pleine, on met empty à false.
if (uniqueInstance == null) peut instancier cette classe //remplir la casserole avec du lait/chocolat
uniqueInstance = new Singleton(); empty=false; boiled=false;
}
} Pour vide la casserole, elle doit
return uniqueInstance; Cette méthode nous offre une manière public void drain(){ être pleine et déjà mixée. une
} pour instancier la classe Singleton if (!empty && boiled){ fois vidée, on met empty à true.
//vider la casserole
empty=true;
Si uniqueInstance n’est pas à nul, ça veut dire }
qu’elle a été créée précédemment }
public static void main(String args[]) { public void boil(){ Pour mixer le contenu de la
Singleton s= Singleton.getInstance(); if (!empty && !boiled){ casserole, elle doit être pleine et
} //faire bouillir non déjà mixée. Lorsqu’elle est
} boiled=true; pleine, on met boiled à true.
}
}
}
97 98
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Singleton : Singleton :
L’usine de chocolat (6/12) Le patron Singleton(7/12)
 Améliorer le code de l’usine de chocolat en le transformant en Singleton
public class ChocolateBoiler {  Définition: Singleton
private boolean empty;  Le patron Singleton assure une seule instance pour une
private boolean boiled;
private static ChocolateBoiler uniqueInstance; classe, et offre un point d’accès global à cette classe.
private ChocolateBoiler() {
empty=true; boiled=false;
}

public static ChocolateBoiler getInstance() {


if (uniqueInstance == null)
uniqueInstance = new ChocolateBoiler();
return uniqueInstance;
}
//reste du code…
}

99 100
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Singleton: Singleton :
Le diagramme de classes du patron (8/12) 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
La variable de classe uniqueInstance UniqueInstance
tient la seule instance du Singleton public static ChocolateBoiler
getInstance() null
Singleton public static ChocolateBoiler null
getInstance()
- static uniqueInstance
if (uniqueInstance == null) null
//autre données utiles
if (uniqueInstance == null) null
+ static getInstance()
uniqueInstance = new Object1
//autre méthodes utiles ChocolateBoiler();
La méthode getInstance() est statique. Object1
return uniqueInstance;
C’est une méthode de classe qu’on peut
y accéder partout dans le code avec uniqueInstance = new Object2
Singleton.getInstance(). Il s’agit d’une ChocolateBoiler();
instanciation facile de cette classe return uniqueInstance; Object2

101 102
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Singleton : Singleton :
Gestion du multi-threading (10/12) Gestion du multi-threading (11/12)
 Solution 1: synchroniser l’accès à la méthode getInstance()  Solution 2: création au moment de la définition de la variable de classe
Initialisation par le JVM avant accès des threads
public class Singleton { public class Singleton {
private static Singleton uniqueInstance; private static Singleton uniqueInstance = new Singleton();
Un seule thread peut accéder,
private Singleton() {} à la fois, à cette méthode private Singleton() {}

public static synchronized Singleton getInstance(){ public static Singleton getInstance(){


if (uniqueInstance == null) return uniqueInstance;
uniqueInstance = new Singleton(); } Il y a déjà une instance, il faut
//autre méthodes utiles juste la retourner
return uniqueInstance; }
}
//autre méthodes utiles
}

 Inconvénient: synchronized réduit la performance d’un facteur de 100  La JVM crée une instance de Singleton lors du chargement de la classe. La JVM
 Si la méthode getInstance() n’est pas critique pour notre application, on peut garantit que l’instance va être créée avant que les threads accèdent la variable
se contenter de cette solution statique uniqueInstance.
103 104
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Singleton :
Gestion du multi-threading (12/12) Récapitulatif (1/2)
 Solution 3: réduire l’utilisation de la synchronisation dans getInstance()  Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage
Le mot clé volatile assure que les threads gèrent la variable  Principes de l’OO
uniqueInstance correctement au moment de son initialisation  Encapsuler ce qui varie
public class Singleton {
 Favoriser la composition sur l’héritage
private volatile static Singleton uniqueInstance;
 Programmer avec des interfaces et non des implémentations
private Singleton() {}  Opter pour une conception faiblement couplée
 Les classes doivent être ouvertes pour les extensions et fermées pour les
public static Singleton getInstance(){ On synchronise seulement la
if (uniqueInstance == null) { première fois modifications
synchronized(Singleton.class) {  Dépendre des abstractions. Ne jamais dépendre de classes concrètes
if (uniqueInstance == null)  Patron de l’OO
uniqueInstance = new Singleton();  Strategy: définit une famille d’algorithmes interchangeables
}
 Observer: définit une dépendance1-à-plusieurs entre objets.
}
return uniqueInstance;  decorator: attache des responsabilités additionnelles à un objet dynamiquement.
}  Abstract Factory: offre une interface de création de familles d’objets
//autre méthodes utiles  Factory Method: définit une interface de création des objets
}
 Singleton: assure à une classe une seule instance et lui offre un point d’accès global
*volatile: inclus à java depuis jdk5
105 106
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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 Le patron
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
"Command"
application multi-thread

107 108
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Home-Automation : Home-Automation :
Spécification (1/28) Analyse du contrôleur distant (2/28)
 Objectif: Mettre en œuvre un système de contrôle distant
d’un ensemble d’appareils dans une maison Il y a des boutons on et off
pour chaque slot
 Besoin: programmer les fonctionnalités d’un contrôleur
distant (avec 7 slots) selon des classes (prédéfinies par le Ces deux boutons ont utilisés
pour contrôler la télévision
vendeur) de gestion des appareils installés dans la maison. Il y a 7 slots à programmer.
On met un appareil différent Ces deux boutons ont utilisés
 Conception: OO dans chaque slot, et on le pour contrôler la chaine Stéreo,
contrôle à travers les boutons etc…
 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.. Un bouton global UNDO
pour annuler l’action du
dernier bouton activé
Contrôleur distant

109 110
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Home-Automation : Home-Automation :
Les classes du vendeur (3/28) Discussion de la conception (4/28)
 Les classes du vendeur nous donnent une idée sur les fonctionnalités
 On s’attendait à des classes avec des méthodes on()-off()
des appareils installés dans la maison :
pour bien correspondre avec le contrôleur distant
Faucet AirCondition
Stereo Appliance
setTemperature()
 C’est important de voir ça comme séparation des
on() openValue()
on()
off() closeValue() préoccupation : le contrôleur doit savoir comment
off()
setCD()
Security
interpréter l’appui sur le bouton et créer des requêtes, mais
setRadio()
setVolume() Light GarageDoor arm()
il ne doit pas connaitre beaucoup sur les appareils et leurs
on() up() desarm() manières de fonctionnement (comment allumer une lampe)
off() down()
stop()  En d’autre terme, le contrôleur émet des requêtes génériques
GardenLight lightOn() OutDoorLight
CeilingLight
 Une entité prendra en charge la transformation de cette requête
lightOff() on()
setDuskTime() en action
setDawnTime() on() off()
manualOn() off()
dim() Sprinkler
manualOff()
waterOn()
waterOff()
111 112
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Home-Automation : Command :
Discussion de la conception (4/28) Commander un dîner (5/28)
 Comment émettre des requêtes à des objets Order
 sans rien connaître des opérations demandées ?
 ou sans rien connaître de celui à qui la requête est destinée ?

 Dissocier (découpler) l’objet qui invoque une opération de


 Le client donne sa
l’objet qui possède les connaissances nécessaires pour commande à la serveuse
réaliser cette opération.
Waitress
 En d’autre terme, le contrôleur émet des requêtes génériques Customer

 Une entité prendra en charge la transformation de cette requête  La serveuse récupère la


commande et la met sur le
en action comptoir, et la lance
 Utiliser le patron Command
 Objet Command: Encapsuler une requête sous forme d’objet  Le cuisinier prépare le
repas selon la commande
Order-Cook
113 114
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Command : Command :
Etudes des interactions (6/28) Je veux
Les rôles et les responsabilités (7/28)
un burger,  La commande (papier) est une requête pour préparer le repas
un shake et  S’il s’agit d’un objet, il peut être passé de la serveuse au comptoir
createOrder() des frites
 Son interface consiste à une seule méthode orderUp(), qui encapsule les actions
nécessaires pour préparer le repas
Il y a toutes les
instructions  La serveuse n’a besoin de savoir comment préparer le repas!
nécessaires pour takeOrder()  La tâche de la serveuse est de prendre la commande et d’invoquer
préparer le repas la méthode orderUp() dessus
 La méthode takeOrder() de la serveuse peut être paramétrée avec différentes
La serveuse récupère la
orderUp() commandes de plusieurs clients. Ceci ne la dérange pas car elle sait que orderUp()
commande et la met sur le
supporte sa commande
comptoir, et la lance
 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
Le cuisinier suit nécessaires pour créer le repas
makeBurger(), makeShake(), makeShips()
les instructions
de la commande
 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
output()
115 116
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Command : Command :
Du dîner vers le patron Commande (8/28) Correspondance (9/28)
Le client crée la commande.
L’objet Command offre une
public void execute(){
receiver.action1();
action1()
action2()
La commande consiste à un Dîner Command Pattern
….. ensemble d’actions et un receveur
seule méthode execute() receiver.action2();
}
qui encapsule les actions create Serveuse Command
createCommandObject( ) Command
Object (Waitress)
execute() 
Cuisinier execute()
setCommand() (Order-Cook)
  Plus tard, le client
demande à l’invoker orderUp() Client
setCommand()
d’exécuter sa commande
execute() Commande invoke
execute()
(Order)
de ceci résulte Client Receiver
action1(), action2() action1() l’invocation des (Customer)
L’invoker appelle la méthode action2() actions sur le
execute() de l’objet Command ….. Receiver takeOrder() setCommand()
117 118
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Command : Home-Automation :
Le patron Command (10/28) Des Commandes (11/28)
Une requête encapsulée

 Définition: Command
action()
 Le patron Command encapsule une requête comme un execute()
execute()

objet, ainsi il nous permet de paramétrer d’autres objets


avec différentes requêtes, files d’attentes ou longues execute(){
receiver.action()
requêtes, et supporte l’annulation d’une opération }
execute() execute()

119 120
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Command : Home-Automation :
Le diagramme de classes du patron (12/28) Notre premier objet Commande (13/28)
L’invoker tient la commande et Interface de tous les commandes.
Le client est responsable de
créer une ConcretCommand à un certain moment demande La commande est invoquée à travers  Implémentons l’interface Command
à la commande de réaliser une sa méthode exécute, qui demande
et affecter son Receiver public interface Command{
requête en exécutant sa au Receiver de réaliser des actions
public void execute();
méthode execute() }

Client Invoker
<<interface>>  Implémentons une Commande pour allumer la lumière
Command
setCommand() Light
execute()
undo() on()
off()

public class LightOnCommand implements Command {


Light light;
public LightOnCommand(Light light){
Receiver ConctretCommand
this.light = light;
action() execute() }
undo() public void execute(){
light.on();
Le Receiver connait comment réaliser le public void execute(){ }
travail demandé afin de satisfaire la requête. receiver.action(); }
Le ConcretCommand définit une lisaison }
121 122
entre une actionRiadh
et un Receiver
BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Home-Automation : Home-Automation :
Notre premier objet Commande (14/28) Notre premier objet Commande (15/28)
 Utilisons l’objet Commande  Testons la fonctionnalité du contrôleur distant

public class SimpleRemoteControl{ public class RemoteControlTest{


Command slot; public static void main(String argv[]) {
SimpleRemoteControl remote = new SimpleRemoteControl();
public SimpleRemoteControl() {} Light light=new Light();
LightOnCommand lightOn=new LightOnCommand (light);
public void setCommand(Command command ){
slot=command; remote.setCommand(lightOn); //passer la commande à l’invoker
} remote.buttonWasPressed(); //simuler l’appui sur le bouton

public void buttonWasPressed(){ }


slot.execute();
}
}

123 124
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Home-Automation : Home-Automation :
2ème Commande (16/28) Une autre Commande (17/28)
 Développer la classe GarageDoorOpenCommand  Ajoutant cette commande au slot du contrôleur distant
GarageDoor public class RemoteControlTest{
public static void main(String argv[]) {
up()
SimpleRemoteControl remote = new SimpleRemoteControl();
down()
Light light = new Light();
stop()
LightOnCommand lightOn=new LightOnCommand(light);
lightOn()
lightOff()
GarageDoor garageDoor = new GarageDoor();
GarageDoorOpenCommand garageOpen = new
public class GarageDoorOpenCommand implements Command { GarageDoorOpenCommand(garageDoor);
GarageDoor garageDoor;
public GarageDoorOpenCommand (GarageDoor garageDoor){ remote.setCommand(lightOn); //encapsuler la commande
this.garageDoor = garageDoor; remote.buttonWasPressed(); //allumer la lumière
}
public void execute(){ remote.setCommand(garageOpen); //encapsuler la commande
garageDoor.up(); remote.buttonWasPressed(); //ouvrir la porte du garage
garageDoor.lightOn();
} }
}
125 126
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Home-Automation : Home-Automation :
Le contrôleur distant (18/28) Le diagramme de classes (19/28)
execute()
execute() <<interface>>
Le client RemoteControl
Command
Light onCommands execute()
Garage offCommands
Door execute() RemoteLoader
Stereo setCommand()
execute() onButtonWasPushed()
offButtonWasPushed()

execute()

execute()

Light LightOnCommand
Les actions de la méthode execute() on()
sont invoquées sur le Receiver execute()
off()
LightOffCommand
L’invoker Contrôleur distant execute() public void execute(){
off() light.on();
on() public void execute(){
}
127 128 light.off();
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] } Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Home-Automation : Home-Automation :
Programmer le contrôleur distant (20/28) Programmer les commandes (21/28)
class RemoteControl{
Command onCommands[];
Command offCommands[];
 Programmer les classes suivantes:
public RemoteControl() {
onCommands = new Command[7];  Light.java, Stereo.java
offCommands = new Command[7];
Command noCommand = new NoCommand(); Eviter la gestion de null  LightOnCommand,.java LightOffCommand.java,
for(int i=0;i<7;i++){
onCommands[i] = noCommand; StereoOnWithCDCommand.java, StereoOffCommand.java
offCommands[i] = noCommand;
} } class LightOnCommand class StereoOnWithCDCommand
public void setCommand(int slot, Command onCommand,Command offCommand ){ implements Command {
onCommands[slot] = onCommand; implements Command {
Light light; Stereo stereo;
offCommands[slot] = offCommand;
} public LightOnCommand(Light public StereoOnWithCDCommand(Stereo
public void onButtonWasPressed(int slot){ light){ stereo){
onCommands[slot].execute(); this.stereo = stereo;
} this.light = light;
public void offButtonWasPressed(int slot){ } }
offCommands[slot].execute(); public void execute(){ public void execute(){
} light.on(); stereo.on();
public String toString(){ stereo.setCD();
String s=""; }
for(int i=0;i<7;i++){ } stereo.setVolume(11);
s+="Slot["+i+"] "+onCommands[i].getClass().getName() +" }
"+offCommands[i].getClass().getName()+"\n"; }
} return s;
}}
129 130
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Home-Automation : Home-Automation :
Tester le contrôleur (22/28) Undo: Annuler la dernière opération (23/28)
class RemoteLoader{  Implémentons l’interface Command
public static void main(String arg[]){
public interface Command{
RemoteControl remoteControl = new RemoteControl();
public void execute();
Light livingRoomLight=new Light();
public void undo();
LightOnCommand livingRoomLightOnCommand = new
}
LightOnCommand(livingRoomLight);
LightOffCommand livingRoomLightOffCommand = new
 Implémentons une Commande pour allumer la lumière
LightOffCommand(livingRoomLight);
remoteControl.setCommand(0, livingRoomLightOnCommand,livingRoomLightOffCommand); public class LightOnCommand implements Command { Light
Light light;
remoteControl.onButtonWasPressed(0); on()
public LightOnCommand(Light light){
remoteControl.offButtonWasPressed(0); off()
Stereo stereo = new Stereo(); this.light = light;
StereoOnWithCDCommand stereoOnWithCDCommand = new }
StereoOnWithCDCommand(stereo); public void execute(){
StereoOffCommand stereoOffCommand = new StereoOffCommand(stereo); light.on();
remoteControl.setCommand(1,stereoOnWithCDCommand,stereoOffCommand); }
remoteControl.onButtonWasPressed(1); public void undo(){ Opération à exécuter en cas
remoteControl.offButtonWasPressed(1); light.off(); d’annulation de cette commande
System.out.println(remoteControl.toString()); }
} }
}
131 132
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Home-Automation : Home-Automation :
Undo: Annuler la dernière opération (24/28) Tester le contrôleur avec UNDO (25/28)
class RemoteControl{
Command onCommands[]; Annuler l’allumage de la lumière
Command offCommands[];
Command undoCommand; C’est ou on stockera la dernière class RemoteLoader{
public RemoteControl() { commande exécutée pour le bouton undo public static void main(String arg[]){
onCommands = new Command[7]; //…
offCommands = new Command[7]; remoteControl.onButtonWasPressed(0);
Command noCommand = new NoCommand(); remoteControl.undoButtonWasPressed();
for(int i=0;i<7;i++){
onCommands[i] = noCommand;
offCommands[i] = noCommand; //…
} Initialisation à NoCommand afin
undoCommand = noCommand; } remoteControl.onButtonWasPressed(1);
d’éviter le traitement de null
public void onButtonWasPressed(int slot){ remoteControl.offButtonWasPressed(1);
onCommands[slot].execute(); System.out.println(remoteControl.toString());
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
}² 133 134
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Home-Automation : Home-Automation :
La Macro-Commande (26/28) MacroCommand (27/28)
 C’est le regroupement de plusieurs commandes en une seule  Créer les macro-commandes
public class MacroCommand implements Command { Stocker les commandes
Command [] commands; Command [] on = {lightOnCommand, stereoOnWithCDCommand, tvOnCommand};
de la macro-commande
public MacroCommand (Command [] commands){ Command [] off = {lightOffCommand, stereoOffWithCDCommand, tvOffCommand};
this.commands = commands;
} Un boucle pour exécuter Les commandes sous
public void execute(){ toutes les commandes de la MacroCommand onMacro= new MacroCommand(on); formes de tableau
for (int i=0;i<commands.length;i++) macro-commande MacroCommand offMacro= new MacroCommand(off);
commands[i].execute();
}  Affecter les macro-commandes à un bouton
}
remoteControl.setCommand(2, onMacro, offMacro);
 Créer les commandes à mettre dans la macro-commande
Affecter les macro-commandes
LightOnCommand lightOnCommand = new LightOnCommand(light);
StereoOnWithCDCommand stereoOnWithCDCommand = new
 Exécuter la macro-commande au bouton du slot n°2
StereoOnWithCDCommand(stereo); System.out.println("Macro On");
TVOnCommand tvOnCommand = new TVOnCommand(tv); remoteControl.onButtonWasPushed(2);
Créer les commandes System.out.println("Macro Off"); Tester ces macro-commandes et
//créer aussi les Off-Commandes remoteControl.offButtonWasPushed(2); donner le résultat de l’exécution

135 136
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
Autre utilisation du patron Command :
Organiser les queues de requêtes (28/28) Récapitulatif (1/2)
 Les commandes nous offrent une manière de execute()
 Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage
paquetage les morceaux de calcul (computation).  Principes de l’OO
Les calculs (commandes créées par des applications)  Encapsuler ce qui varie
execute()
seront placés dans des queues (queue de jobs) pour  Favoriser la composition sur l’héritage
être exécutés. execute()  Programmer pour des interfaces
 Opter pour une conception faiblement couplée
execute()
 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
C’est une manière efficace  Patron de l’OO
pour limiter le calcul à un  Strategy: définit une famille d’algorithmes interchangeables
nombre fixé de Threads
execute()
 Observer: définit une dépendance1-à-plusieurs entre objets.
Les threads récupèrent les commandes  Decorator: attache des responsabilités additionnelles à un objet dynamiquement.
de la queue une à une, et appellent leur  Abstract Factory: offre une interface de création de familles d’objets
méthode execute(). Une fois complété,  Factory Method: définit une interface de création des objets
execute() execute()
ils retournent pour une nouvelle
commande.  Singleton: assure à une classe une seule instance
 Command: encapsule une requête comme un objet
137 138
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Récapitulatif (2/2) Exercice 1


 Le patron Command découple un objet, faisant des requêtes, de l’objet  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
qui sait comment la réaliser
complexité plus ou moins élevé. Les dessins pourront être composés d’un
 Un objet Command est au centre de ce découplage et encapsule le ensemble de points, droites, arc de cercles ou autres formes simples telles que
Receiver avec une action (ou des actions) des cercles ou des polygones. Cet outil sera similaire au programme appelé
 L’Invoker exécute la requête d’un objet Command en appelant sa «Paint» sous l’environnement Windows. La figure suivante présente un
méthode execute(), qui invoque les actions sur le Receiver diagramme de classes simplifié pour cette application :
 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 Application
 Vous êtes chargé de concevoir le mécanisme
système (avant l’exécution de la méthode execute()) + ouvrir(doc : Dessin)  qui permettra de garder une trace des actions
de l’utilisateur. Ce dernier pourra ainsi annuler
+ fermer() 

 Les Macro-Commandes sont des simples extensions de Command qui + sauvegarder() : boolean

les dernières actions faites.


permettent linvocation de multiple commandes. Pareil, les macro-
commandes peuvent supporter les méthodes d’annulation (undo). Dessin
+ ajouterPoint(position : Vecteur2D) 
 Question: Faites les modifications nécessaires
 Le patron Command est utilisé aussi pour implémenter l’organisation + ajouterDroite(pt1 : Vecteur2D, pt2 : Vecteur2D) 
+ ajouterCercle(rayon : float, centre : Vecteur2D) 
au diagramme de classes pour implanter le
des requêtes (Jobs) et la gestion de la journalisation (logging) + ajouterPolygone(listePts : []Vecteur2D) 
+ afficher()
patron Commande.
139 140
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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 *) 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 :
Le Modèle-Vue-
public class Client {
public static void main(String[] args) {
Contrôleur
Calculatrice c=new Calculatrice();
PlusCommand plus =new PlusCommand(c);
MultipCommand mult=new MultipCommand (c);
SoustCommand sous =new SoustCommand(c);
CalculatriceControl control =new CalculatriceControl();
control.setCommand(0, plus);
control.setCommand(1, sous);
control.setCommand(2, mult);
control.MultiButtonPressed(2, 5, 15);
control.SoustButtonPressed(1, 17, 10);
control.PlusButtonPressed(0, 12, 15); }}
141 142
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Architecture Modèle/Vue/Contrôleur Le Modèle


 Le modèle MVC: destiné à répondre aux besoins des applications
interactives en séparant les problématiques liées aux différents  Le modèle représente le cœur (algorithmique) de l'application :
composants au sein de leur architecture respective. traitements des données, interactions avec la base de données, etc.
 décrit les données manipulées par l'application.
 Ce paradigme regroupe les fonctions en trois catégories :
 regroupe la gestion de ces données et est responsable de leur intégrité.
 un modèle (modèle de données),
 La base de données sera l'un de ses composants.
 une vue (présentation, interface utilisateur)
 un contrôleur (logique de contrôle, gestion des événements, synchronisation)  Le modèle comporte des méthodes standards pour mettre à jour
ces données (insertion, suppression, changement de valeur).
 Les résultats renvoyés par le modèle ne s'occupent pas de la
L'idée est de bien séparer les présentation.
données, la présentation et les
 Le modèle ne contient aucun lien direct vers le contrôleur ou la vue.
traitements.
 Sa communication avec la vue s'effectue au travers du patron
Observateur.

143 144
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
La Vue 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
 Ce avec quoi l'utilisateur interagit se nomme précisément la vue.  reçoit tous les événements de l'utilisateur et enclenche les actions à
 présenter les résultats renvoyés par le modèle. effectuer
 recevoir toute action de l'utilisateur (hover, clic de souris, sélection d'un bouton radio,  Si une action nécessite un changement des données, le contrôleur
cochage d'une case, entrée de texte, de mouvements, de voix, etc.). demande la modification des données au modèle, et ce dernier notifie la
 Ces différents événements sont envoyés au contrôleur. vue que les données ont changé pour qu'elle se mette à jour.
 La vue n'effectue pas de traitement,  D'après le patron de conception observateur/observable, la vue
 afficher les résultats des traitements effectués par le modèle et interagir avec est un « observateur » du modèle qui est lui « observable »
l'utilisateur.  Le contrôleur n'effectue aucun traitement, ne modifie aucune donnée.
 Plusieurs vues peuvent afficher des informations partielles ou non d'un même  Il analyse la requête du client et se contente d'appeler le modèle adéquat et de
modèle. renvoyer la vue correspondant à la demande.

145 146
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Flux de traitement Architecture MVC ou 3-Tier


 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  L'architecture trois tiers est un modèle en couches, c'est-à-dire, que chaque
exemple un clic de souris pour lancer un traitement de données) ; couche communique seulement avec ses couches adjacentes
 le contrôleur demande au modèle approprié d'effectuer les traitements et  le flux de contrôle traverse le système de haut en bas
notifie à la vue que la requête est traitée (via par exemple un callback) ;  Dans le modèle MVC, la vue peut consulter directement le modèle (lecture)
sans passer par le contrôleur. Par contre, elle doit nécessairement passer
 la vue notifiée fait une requête au modèle pour se mettre à jour (par exemple par le contrôleur pour effectuer une modification (écriture).
affiche le résultat du traitement via le modèle).  le contrôleur peut alors envoyer des requêtes à toutes les vues de manière à ce
qu'elles se mettent à jour.
 La différence fondamentale se trouve dans le fait que l'architecture 3-Tier
sépare la couche métier de la couche accès aux données.
 Pour qu'une application MVC soit une vraie application 3-Tier il faut lui ajouter une
couche d'abstraction d'accès aux données de type DAO (Data Access Object).
 Inversement pour qu'une application 3-Tier respecte MVC il faut lui ajouter une
couche de contrôle entre la couche métier et la couche présentation.

147 148
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [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

Le patron
Pizza pizza=new Pizza(); interface, sauf qu’on ne peut pas
instancier l’un des deux derniers!
pizza.prepare();

"Factory"
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}

 On veut plus qu’un type de pizza….

149 150
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Plusieurs types de pizza (2/37) Autres types de pizza (3/37)
 Les concurrents ont ajouté un nouveau type de pizza: (avec Calamars)
 Pizzeria: Créer plusieurs types de pizza
 Ajouter ClamPizza au menu
On passe le type du pizza à travers
Pizza orderPizza( String type ){
le méthode orderPizza()  On n’a pas vendu beaucoup de GreekPizza dernièrement
Pizza pizza;
 Suspendre GreekPizza du menu
if (type.equals("cheese"){ Pizza orderPizza(String type){
pizza=new CheesePizza(); Pizza pizza;
} else if (type.equals("greek"){ Selon le type de pizza, on crée la if (type.equals("cheese"){

Ce code est NON fermé


pizza concrète, et on la place dans

pour la modification!
pizza=new GreekPizza(); pizza=new CheesePizza();
} else if (type.equals("pepperoni"){ la variable "pizza" (interface et } else if (type.equals("greek"){ Partie variable: On modifie
pizza=new PepperoniPizza(); classe mère des pizzas). pizza=new GreekPizza(); le code autant que la
} } else if (type.equals("pepperoni"){ sélection de pizza change.
pizza=new PepperoniPizza();
pizza.prepare(); } else if (type.equals("clam"){
pizza.bake(); Une fois on a la pizza, on prépare la sauce, le pizza=new ClamPizza();
pizza.cut(); nappage (tomate/crême fraiche) et le fromage , }
pizza.box(); puis on la fait cuire, la coupe, et on la met dans pizza.prepare();
return pizza; une boite. pizza.bake(); Partie invariable: Généralement, ces opérations
} pizza.cut(); sont les mêmes pour des années et des années.
pizza.box();
return pizza;
151 152 }
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Encapsuler la création (4/37) Un Simple Factory (5/37)
 Règle 1 de l’OO: Encapsuler ce qui varie  Le seul rôle de SimplePizzaFactory est de créer des pizzas pour ces
if (type.equals("cheese"){
clients
pizza=new CheesePizza(); Initialement, on définit la méthode
} else if (type.equals("pepperoni"){ createPizza() dans le Factory. C’est la
pizza=new PepperoniPizza();
public class SimplePizzaFactory { méthode que tous les clients utilisent
} else if (type.equals("clam"){
public Pizza createPizza(String type){ pour instancier des nouveaux objets.
Pizza pizza=null;
pizza=new ClamPizza();
}
Pizza orderPizza(String type){ if (type.equals("cheese"){
Pizza pizza; pizza=new CheesePizza();
} else if (type.equals("pepperoni"){
On place ce code dans un objet qui s’occupera de la pizza=new PepperoniPizza();
création des pizzas concrètes. Si un autre objet a besoin } else if (type.equals("clam"){
d’une pizza concrète, c’est cet objet qu’il faut appeler. pizza=new ClamPizza();
pizza.prepare(); } C’est le code qu’on a retirer de la
pizza.bake(); méthode orderPizza().
pizza.cut(); return pizza;
pizza.box(); }
return pizza; }
}

153 OnRiadh
attribue le nom Factory à ce nouvel objet 154
BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Retravaillons la classe PizzaStore (6/37) Le diagramme de classes (7/37)
 Maintenant, PizzaStore utilise SimplePizzaFactory pour créer des pizzas Elle doit être la seule partie de On définit Pizza comme
notre application qui pointe vers les classe abstraite, avec quelque
PizzaStore récupère la classes des pizzas concrètes implémentations qui peuvent
public class PizzaStore {
référence du factory à être redéfinies
SimplePizzaFactory factory;
travers le constructeur.
public PizzaStore(SimplePizzaFactory factory){ PizzaStore SimplePizzaFactory Pizza
this.factory=factory;
} prepare()
orderPizza() createPizza() bake()
public Pizza orderPizza(String type){
Pizza pizza; cut()
box()
La méthode de création
pizza=factory.createPizza(type);
est souvent statique
pizza.prepare();
pizza.bake(); La méthode orderPizza() utilise le CheesePizza ClamPizza
PizzaStore crée des PepperoniPizza
pizza.cut(); factory pour créer ses pizzas. instances à travers
pizza.box();
return pizza; SimplePizzaFactory
}
} Chaque produit implémente la classe abstraite Pizza
 Noter qu’on a remplacé l’opérateur new par une méthode concrète  Actuellement, Simple Factory n’est pas un patron. C’est plutôt un
 Plus d’instanciation concrète ici "style" de programmation
155 156
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Franchise de PizzaStore (8/37) Différent styles des PizzaStores (9/37)
 Objectif: Franchiser PizzaStore: Créer plusieurs stores dans  Si on prépare les mêmes pizzas Créer des pizzas à travers
SfaxPizzaFactory
plusieurs villes (Sfax, Tunis, etc.)
SfaxPizzaFactory sffactory = new SfaxPizzaFactory();
 Besoin: Développer une application qui gère la création des PizzaStore sfstore = new PizzaStore(sffactory);
pizzas pour chaque store sfstore.orderPizza("cheese"); Créer les mêmes pizzas à
travers TunisPizzaFactory
 Chaque store offre différent types de pizza
 Conception: OO TunisPizzaFactory tnfactory = new TunisPizzaFactory();
PizzaStore tnstore = new PizzaStore(tnfactory);
tnstore.orderPizza("cheese");
Moins de fromage dans
les pizzas, etc.
 Et si chaque PizzaStore prépare ses propres styles de pizza
Je prépare les pizzas depuis des
années et je veux ajouter mes propres
Des pizzas familles de touches d’amélioration des procédures de
grande taille, beaucoup mon PizzaStore
de fromage, etc.
157 158
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Le framework de PizzaStore (10/37) Les styles de pizzas (11/37)
 On donne la liberté aux franchises de créer leurs propres styles PizzaStore Méthode abstraite, à définir
dans les classes dérivées
 Déplacer la création dans une la méthode createPizza() et garder la createPizza()
orderPizza()
même méthode orderPizza() pour tous les stores
 Chaque région l’étend afin de spécifier son propre style
Créer des pizzas
public abstract class PizzaStore { Créer des pizzas SfaxStylePizzaStore TunisStylePizzaStore avec les ingrédients
avec les ingrédients spécifiques à Tunis
spécifiques à Sfax createPizza() createPizza()
public Pizza orderPizza(String type){
Pizza pizza; CreatePizza() est une
méthode PizzaStore plutôt
Pizza createPizza(String type) { Pizza createPizza(String type) {
pizza = createPizza(type); que dans le Factory
Pizza pizza=null; Pizza pizza=null;
pizza.prepare(); if (type.equals("cheese"){ if (type.equals("cheese"){
pizza.bake(); Tout ceci apparaît le même pizza=new SfaxStyleCheesePizza(); pizza=new TunisStyleCheesePizza();
} else if (type.equals("pepperoni"){ } else if (type.equals("pepperoni"){
pizza.cut(); On a transféré notre objet pizza=new SfaxStylePepperoniPizza(); pizza=new TunisStylePepperoniPizza();
pizza.box(); Factory dans cette méthode } else if (type.equals("clam"){ } else if (type.equals("clam"){
return pizza; pizza=new SfaxStyleClamPizza(); pizza=new TunisStyleClamPizza();
} } }
abstract Pizza createPizza(String type); return pizza; return pizza;
}
} }
Notre "méthode Factory" est
159 160
maintenant abstraite dans
Riadh PizzaStore
BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Un PizzaStore de Style Sfaxien (12/37) Commander des pizzas (13/37)
 Les bénéfices d’une franchise Je voudrai une pizza Je voudrai une pizza
 On obtient des fonctionnalités des pizzas communes (prepare(), bake(), cut() et box()) de grande taille avec beaucoup de taille moyenne avec
 Chaque région définit sa propre méthode createPizza() qui spécifie son style de pizza de fromage du style peu de fromage et au thon
tunisien du style sfaxien
public class SfaxStylePizzaStore extends PizzaStore {
Pizza createPizza(String item) { On hérite la méthode
if (item.equals("cheese"){ orderPizza() de PizzaStore PizzaStore tunisps = PizzaStore sfaxps =
return new SfaxStyleCheesePizza(); new TunisStylePizzaStore(); new SfaxStylePizzaStore();
} else if (item.equals("pepperoni"){
On implémente createPizza()
return new SfaxStylePepperoniPizza();
puisqu’elle est abstraite: Instance du store spécifique
} else if (item.equals("clam"){
C’est la "méthode Factory"
return new SfaxStyleClamPizza();
}
} Créer des pizzas du style sfaxien!!
} Prendre des commandes
 Rq: Toutes les responsabilités d’instanciation sont déplacées vers la méthode
createPizza() qui agit comme un factory tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");
 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- C’est une méthode de l’instance tunisps (respectivement
classes sfaxps), définie dans la classe PizzaStore
161 162
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Commander des pizzas (14/37) Implémenter (15/37) Les créateurs
PizzaStore
tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");  Implémenter les classes: createPizza()
PizzaStore.java, SfaxPizzaStore.java orderPizza()
Factory Method
La méthode orderPizza() appelle createPizza() et TunisPizzaStore.java
SfaxStylePizzaStore TunisStylePizzaStore
createPizza() createPizza()
Pizza pizza= createPizza("cheese"); Pizza pizza= createPizza("cheese");

La méthode createPizza() est implémentée dans la classe dérivée  Implémenter les classes: Pizza.java, Les produits
Elle retourne une pizza au Elle retourne une pizza au SfaxStyleCheesePizza.java, Pizza
fromage style tunisien fromage style sfaxien
SfaxStyleClamPizza.java,
On termine la préparation SfaxStylePepperoniPizza.java,
pizza.prepare(); pizza.prepare(); TunisStyleCheesePizza.java,
pizza.bake(); pizza.bake(); TunisStyleClamPizza.java, SfaxStyleCheesePizza TunisStyleCheesePizza
pizza.cut(); pizza.cut(); TunisStylePepperoniPizza.java SfaxStyleClamPizza TunisStyleClamPizza
pizza.box(); pizza.box();
SfaxStylePepperoniPizza
TunisStylePepperoniPizza

163 164
De style tunisien De style sfaxien
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Le patron Factory Method (16/37) Le diagramme de classes du patron (17/37)
La classe mère de tous les produits Le Creator est une classe qui contient

 Définition: Factory Method concrets. Elle représente aussi le type


générique qui référence vers les
l’implémentation de toutes les
méthodes qui manipulent le produits,
instances des classes concrètes à l’exception de factoryMethod()
 Le patron factory method définit une interface de
création des objets, et laisse les classes-dérivées décider de Product Creator La méthode abstraite
la classe de l’instanciation. La méthode factory permet à factoryMethod() facotoryMethod() que tous
une classe de déléguer l’instanciation à ces classes dérivées. anOperation() les dérivés de la classe
Creator implémentent

Le ConcretCreator
implémente la méthode
facotoryMethod(), qui
ConcretProduct ConctretCreator produit 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
165 166
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Un PizzaStore dépendant (18/37) La dépendance entre les objets (19/37)
 Hypothèse: On n’a jamais entendu parler du factory  Cette version de PizzaStore dépend de tous les objets pizzas parce qu’elle les crée
 Compter le nombre d’objets de pizzas concrètes dont cette classe dépend directement
 Refaire le compte si on ajoute des pizzas de style bizertin  On dit que PizzaStore dépend des implémentations des pizzas parce que chaque
public class DependentPizzaStore { changement des implémentations concrètes des pizzas, affecte le PizzaStore
Pizza createPizza(String style, String type) {
Pizza pizza=null; Si les implémentations des pizzas
if (style.equals("Sfax")){ Gérer toutes les pizzas de
changent, on doit modifier PizzaStore
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(); Pour chaque nouveau type de pizza,
pizza.cut(); on ajoute une autre dépendance dans
pizza.box();
return pizza; la méthode create()
167 } 168
} Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
L’inversion de dépendance (20/37) Appliquons ce principe (21/37)
 Réduire les dépendances aux classes concrètes dans notre code, PizzaStore dépend seulement de
Pizza, qui est une classe abstraite
est une "bonne chose" Pizza est une classe
abstraite.. abstraction
 Le principe qui formalise cette notion s’appelle "principe Les classes de pizzas concrètes dépendent
d’inversion de dépendance" : aussi de l’abstraction Pizza, parce qu’elles
implémentent l’interface Pizza
 Règle 5: Dépendre des abstractions. Ne jamais dépendre
de classes concrètes.
 Ce principe prétend que nos "haut-niveau" composants ne
doivent pas dépendre de nos "bas-niveau" composants; plutôt, les
deux doivent dépendre des abstractions.
Le "Factory Method"
 Un composant de haut-niveau (PizzaStore) est une classe dont le est la technique la plus
comportement dépend des autres composants de bas- puissante d’adhérence
niveau(Pizza) au principe d’inversion
de dépendance, mais
pas la seule...
169 170
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Les ingrédients des pizzas (22/37) Les menus des pizzas (23/37)
 Problème : quelques franchises n’ont pas utilisé la
même procédure de préparation, et ce en substituant
Sfax Tunis
des ingrédients par d’autres de basse qualité, afin Pizza Menu
Pizza Menu
d’augmenter leur marge. Cheese Pizza
Nous avons les mêmes
familles de produits, mais Cheese Pizza
! Il faut assurer la consistance des ingrédients Sauce marinara, Parmesan,
Emmental différente implémentations Sauce tomate prune, Mozzarella,
Roquefort
selon la région
 Solution : créer un factory qui produit les ingrédients, Clam Pizza
Sauce marinara, Parmesan,
Clam Pizza
Sauce tomate prune, Mozzarella,
et les transporter aux franchises Clovis, Olive verte Palourde, Olive noire
Pepperoni Pizza
 Le seul problème avec ce plan : Ce qui est sauce rouge Sauce marinara, Parmesan,
Pepperoni Pizza
Sauce tomate prune, Mozzarella,
Aubergine, Poivron, Olive verte
à Sfax, n’est pas sauce rouge à Tunis Épinard, Poivre, Olive noire

 Il y a un ensemble d’ingrédients à transporter à Sfax, et un


autre ensemble à transporter à Tunis
171 172
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Les familles des ingrédients (24/37) Les factories des ingrédients (25/37)
Chaque famille correspond à un Tunis  Le factory est le responsable de la création de la pâte, la sauce,
type de sauce, un type de
fromage, un type de légume, et un PlumTomatoSauce le fromage, etc.
Mozzarella Pour chaque ingrédient, on
type d’olive (et d’autres types) public interface PizzaIngredientFactory {
crée une create() méthode
public Dough createDough();
dans notre interface
Spinach public Sauce createSauce();
BlackOlive public Cheeze createCheese();
public veggies[] createVeggies();
public Clam createClam();
Sfax } Beaucoup de nouvelles
classes, une par ingredient
MarinaraSauce
Parmesan
 A faire :
 Construire un facotry pour chaque région: une sous-classe de
Toutes les PizzaStores utilisent PizzaIngredientFactory qui implémente chaque create() méthode
Eggplant les mêmes composants, mais
GreenOlive  Implémenter un ensemble de classes d’ingrédients, à utiliser par les
chaque région possède une factories tels que: OliveVerte, Mozzarella, SauseMarinara, etc.
implémentation spécifique de ces
composants  Lier ceci avec notre ancien code de PizzaStore, tout en travaillant
nos factories d’ingrédients
173 174
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Les factories de Sfax (26/37) Retravaillons la classe Pizza (27/37)

public class SfaxPizzaIngredientFactory implements PizzaIngredientFactory public abstract class Pizza { Les ingrédients d’une paizza
{ String name; (liste non-exhaustive)
public Dough createDough(){ Dough dough;
return new ThinDough(); Pour chaque famille d’ingrédient, on Sauce sauce;
La collecte des ingrédients se fait dans cette
} crée la version sfaxienne Cheese cheese;
méthode (à travers un factory d’ingrédients)
public Sauce createSauce(){ Veggies veggies[];
qui sera définie par les classes dérivées
return new MarinaraSauce(); Clam clam;
} abstract void prepare();
public Cheese createCheese(){ void bake(){
return new Parmesan(); System.out.println("Cuire durant 25mn à 350°");}
} void cut(){
public Veggies[] createVeggies(){ System.out.println("Couper en morceaux à la diagonale");}
Veggies veggies[]={new Garlic(), new Onion(), new Eggplant()}; void box(){
return veggies; System.out.println("Placer la pizza dans un boitier officiel");}
} void setName(String s){
public Clam createClam(){ name=s;}
return new Clovis(); String getName(){ Les autres méthodes sont les
} Palourde() pour le return name;} mêmes (à l’exception de prepare())
} cas de tunis }
175 176
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Retravaillons les classes des Pizzas (28/37) Retravaillons les classes des Pizzas (29/37)
Pour faire la pizza, on besoin d’un
factory. Chaque classe Pizza prend le
factory à travers son constructeur Un factory pour chaque type de Pizza

public class CheesePizza extends Pizza { public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientfactory; PizzaIngredientFactory ingredientfactory;
CheesePizza(PizzaIngredientFactory ingredientfactory){ ClamPizza(PizzaIngredientFactory ingredientfactory){
this.ingredientfactory = ingredientfactory; this.ingredientfactory = ingredientfactory;
} }
void prepare(){ void prepare(){
System.out.println("Préparons " +name); System.out.println("Préparons " +name);
dough = ingredientfactory.createDough(); dough = ingredientfactory.createDough();
sauce = ingredientfactory.createSauce(); sauce = ingredientfactory.createSauce();
cheese = ingredientfactory.createCheese(); cheese = ingredientfactory.createCheese();
} clam= ingredientfactory.createClam();
} Pour faire une ClamPizza, la méthode
} Chaque fois que la méthode prepare() prépare les ingrédients
a besoin d’ingrédient, elle appelle le } correspondants de son factory local.
factory pour le produire Si c’est le factory de sfax, on
va préparer des clovis

177 178
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Retravaillons les PizzaStores (30/37) Factories (31/37)
Le store de Sfax est composé d’un Définit l’interface
factory sfaxien d’ingrédients/
public class SfaxPizzaStore extends PizzaStore {
Pizza createPizza(String item) { Offre les
Abstract Ingredient Factory
Pizza pizza = null; implémentations
PizzaIngredientFactory ingredientfactory= des ingrédients
new SfaxPizzaIngredientFactory();
On passe à chaque pizza le factory
if (item.equals("cheese"){ censé créer ses ingrédients
pizza = new CheesePizza(ingredientfactory);
pizza.setName("Sfax Style Cheese Pizza"); Sfax Tunis
} else if (item.equals("pepperoni"){
pizza = new PepperoniPizza(ingredientfactory);
pizza.setName("Sfax Style Pepperoni Pizza"); De l’abstract factory, on dérive
} else if (item.equals("clam"){ plusieurs concrets factories qui
pizza = new ClamPizza(ingredientfactory); produisent les mêmes produits, mais avec
pizza.setName("Sfax Style Clam Pizza"); différentes implémentations
} En passant (au constructeur) une variété
return pizza; de factories, on obtient une variété
} d’implémentations, tout en gardant le
} même code du client
179 180
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Commander des pizzas (32/37) Commander des pizzas (33/37)
tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");
Je voudrai une pizza Je voudrai une pizza
de grande taille avec beaucoup de taille moyenne avec
de fromage du style La méthode orderPizza() appelle initialement createPizza()
peu de fromage et au thon
tunisien du style sfaxien
Pizza pizza= createPizza("cheese"); Pizza pizza= createPizza("cheese");
PizzaStore tunisps = PizzaStore sfaxps =
La méthode createPizza() implique le factory d’ingrédients
new TunisPizzaStore(); new SfaxPizzaStore();
Pizza pizza= new Pizza pizza= new
Instance du store spécifique CheesePizza(tunisIngeredientFactory); CheesePizza(sfaxIngeredientFactory);

Chaque instance de pizza est associée à un factory d’ingrédients

Prendre des commandes La méthode prepare() est appelée et chaque factory est appelé pour produire les
ingrédients de la région
tunisps.orderPizza("cheese"); sfaxps.orderPizza("cheese");

void prepare(){ void prepare(){


C’est une méthode de l’instance tunisps (respectivement
sfaxps), définie dans la classe PizzaStore
181 182 CheesePizza à la tunisoise CheesePizza à la sfaxienne
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

PizzaStore : PizzaStore :
Commander des pizzas (34/37) Le patron Abstract Factory (35/37)
void prepare(){ void prepare(){
dough = factory.createDough();
// Pâte coustillante
dough = factory.createDough();
// Pâte mince
 Définition: Abstract Factory
sauce = factory.createSauce(); sauce = factory.createSauce();  Le patron abstract factory offre une interface de
// Sauce tomate prune // Sauce marinara
cheese = factory.createCheese(); cheese = factory.createCheese(); création de familles d’objets dépendants (en relation), sans
// Mozzarella, Roquefort // Parmesan, Emmental
} }
spécifier leurs classes concrètes.
Elle prépare une pizza au Elle prépare une pizza au
fromage avec les ingrédients fromage avec les ingrédients
du style tunisien du style sfaxien
On termine la création
pizza.bake(); pizza.bake();
pizza.cut(); pizza.cut();
pizza.box(); pizza.box();

183 184
De style tunisien De style sfaxien
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]
PizzaStore : PizzaStore :
Le diagramme de classes du patron (36/37) La conception finale (37/37) Les clients de l’abstract factory
sont les stores de Sfax et de Tunis
Le client est composé au moment de
l’exécution par un factory concret SfaxPizzaStore
L’abstract factory définit un Client L’abstract factory définit un <<interface>>
ensemble de méthodes pour la l’ensemble des produits qu’on a Clam
production des produits Une famille de produits besoin pour faire une pizza
<<interface>>
AbstractProductA Clovis Palourde
<<interface>> <<interface>>
AbstractFactory PizzaIngredientFactory
createSauce() <<interface>>
createProductA() createCheese() Sauce
createProductB() createClam()
ProductA2 ProductA1 //etc.

MarinaraSauce PlumTomatoSauce
<<interface>>
AbstractProductB
TunisPizzaIngred SfaxPizzaIngredi <<interface>>
ConcretFactory1 ConcretFactory2 ientFActory entFactory Cheese
createProductA() createProductA()
createSauce() createSauce()
createCheese() createCheese()
createProductB() createProductB() ProductB2 ProductB1 createClam() createClam()
Parmesan Mozzarella
Les factories concrets implémentent les La tâche des factories est de produire les
différences familles de produits ingrédients spécifiques à chaque région
185 186 Chaque factory produit différent implémentation
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN
de chaque HALIMA&Wajdi
famille de produits LOUATI [Design patterns]

Récapitulatif (1/2) Récapitulatif (2/2)


 Bases de l’OO: Abstraction, Encapsulation, Polymorphisme & Héritage  Tous les factories encapsule la création des objets
 Principes de l’OO  Malgré qu’il n’est un vrai patron, le "Simpe Factory" est une manière simple
 Encapsuler ce qui varie de découplage de clients des concrètes classes
 Favoriser la composition sur l’héritage  Factory Method repose sur l’héritage: La création d’objet est déléguée aux
 Programmer avec des interfaces et non des implémentations sous-classes qui implémentent la méthode factory de création d’objets
 Opter pour une conception faiblement couplée  Abstract Factory repose sur la composition d’objets: La création d’objet est
 Les classes doivent être ouvertes pour les extensions et fermées pour les implémentée dans une méthode exposée dans l’interface du factory
modifications  Tous les patrons factories soutiennent le faible couplage entre notre
 Dépendre des abstractions. Ne jamais dépendre de classes concrètes application et les classes concrètes.
 Patron de l’OO  L’intension de Factory Method est de permettre à une classe de reporter
 Strategy: définit une famille d’algorithmes interchangeables
l’instanciation à ses sous-classes.
 Observer: définit une dépendance1-à-plusieurs entre objets.
 L’intension d’Abstract Factory est de créer une famille d’objets en relation
sans dépendre de leurs classes concrètes
 Decorator: attache des responsabilités additionnelles à un objet dynamiquement.
 Factory Method: définit une interface de création des objets, et laisse les
 L’inversion de dépendance nous guide afin d’éviter les dépendances des
classes concrètes, et s’efforcer pour les abstractions
classes-dérivées décider de la classe de l’instanciation.
 Factories sont des techniques puissantes de codages des abstractions et non
 Abstract Factory: offre une interface de création de familles d’objets des classes concrètes
dépendants, sans spécifier leurs classes concrètes
187 188
Riadh BEN HALIMA&Wajdi LOUATI [Design patterns] Riadh BEN HALIMA&Wajdi LOUATI [Design patterns]

Vous aimerez peut-être aussi