Académique Documents
Professionnel Documents
Culture Documents
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composit
e
GOF
Mediator
Decorator
Proxy
Mohamed Youssfi, Laboratoire Signaux Systèmes Distribués et Intelligence Artificielle (SSDIA), ENSET Mohammedia, Université Hassan II de Casablanca
Decorator Design Pattern
Design Patterns :
Lab. SSDIA, ENSET Mohammedia,
Université Hassan II de Casablanca Maroc
med@youssfi.net
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Classification GOF des Design Patterns
Pattern Observer
Définition : subscribe
State
Changed
• Le pattern Observer définit une relation entre event
update(state=10)
les objets de type un à plusieurs, de façon que, notify
onStateChanged(10) Observers
lorsqu’un objet change d’état, tous ce qui en
update(state=10)
dépendent en soient informés et soient mis à onStateChanged(10)
jour automatiquement
Définition : subscribe
State
Changed
• Le pattern Observer définit une relation entre event
update()
les objets de type un à plusieurs, de façon que, notify
onStateChanged() Observers
lorsqu’un objet change d’état, tous ce qui en
getState()
dépendent en soient informés et soient mis à update()
jour automatiquement onStateChanged()
getState()
Observé Observateur
Faites connaissance avec le pattern Observateur
Vous savez comment fonctionne un abonnement à un magazine:
3. Chaque fois qu’il y’a une nouvelle édition, vous la recevez. Et tant que vous
êtes abonné, vous recevez les nouvelles éditions.
4. Quand vous ne vouliez pas de ces magazines, vous résiliez votre abonnement.
On cesse alors de vous les livrer.
5. Tant que l’éditeur reste en activité, les particuliers, les hôtels, les compagnies
aériennes, etc., ne cessent de s’abonner et de se désabonner.
• On trouve également une interface Observable qui devra être implémentée par les classes désireuses
de posséder des observateurs.
• La classe ObservableConcret implémente cette interface, ce qui lui permet de tenir informer ses
observateurs. Celle-ci possède en attribut un état (ou plusieurs) et un tableau d’observateurs. L’état est
un attribut dont les observateurs désirent suivre l’évolution de ses valeurs. Le tableau d’observateurs
correspond à la liste des observateurs qui sont à l’écoute.
• En effet, il ne suffit pas à une classe d’implémenter l’interface Observateur pour être à l’écoute, il faut
qu’elle s’abonne à un Observable via la méthode ajouterObservateur(Observateur).
Implémentation
La classe ObservableConcret dispose de quatre méthodes :
• ajouterObservateur(Observateur),
• supprimerObservateur(Observateur),
• notifierObservateurs()
• getEtat().
Les deux premières permettent, respectivement, d’ajouter des observateurs à l’écoute de la classe et d’en supprimer.
En effet, le pattern Observateur permet de lier dynamiquement (faire une liaison lors de l’exécution du programme par opposition à lier
statiquement à la compilation) des observables à des observateurs.
La méthode notifierObservateurs() est appelée lorsque l’état subit un changement de valeur. Celle-ci avertit tous les observateurs de cette
mise à jour.
La méthode getEtat() est un simple accesseur en lecture pour l’état. En effet, les observateurs récupèrent via la méthode
actualiser(Observable) un pointeur vers l’objet observé. Puis, grâce à ce pointeur, et à la méthode getEtat() il est possible d’obtenir la valeur
de l’état.
Implémentation
Il existe une variation possible lors de l’utilisation de ce pattern.
• TIRER : Dans la solution présentée, une référence vers l’objet observable est mis à disposition de chaque observateur.
Ainsi les observateurs peuvent l’utiliser pour appeler la méthode getEtat() et ainsi obtenir l’état de l’observable. Cette
solution est nommée « TIRER » car c’est aux observateurs, une fois avertis de l’évolution, d’aller chercher l’information
sur l’état.
• POUSSER :Mais il existe la solution inverse appelée « POUSSER ». Dans ce cas, on passe directement l’état actuel de
l’observable dans la méthode actualiser(TypeEtat). Ainsi les observateurs disposent directement de l’état.
Qu’elle est la meilleur solution entre les deux ? C’est la première parce qu’elle permet une fois de plus de lier faiblement
l’observable à ses observateurs. En effet, si l’observateur dispose d’un pointeur vers l’objet observable et que la classe
observable évolue en ajoutant un deuxième état. L’observateur souhaitant se tenir informé de ce deuxième état aura juste à
appeler l’accesseur correspondant. Alors que si on « POUSSER » il faudrait changer la signature de la méthode ce qui peut
s’avérer plus dommageable.
Interface Observable
package obs;
}
Interface Observer
package obs;
}
Une implémentation de Observable
package obs;
@Override
@Override
@Override
}
Une implémentation de Observer
package obs;
@Override
public void update(Observable o) {
int nouvelEtat=((ObservableImpl)o).getEtat();
System.out.println("Observer 1 a reçu la nouvelle valeur de état
:"+nouvelEtat);
}
}
Une autre implémentation de Observer
package obs;
@Override
public void update(Observable o) {
int nouvelEtat=((ObservableImpl)o).getEtat();
System.out.println("Observer 2 Mise à jour avec état:"+nouvelEtat);
}
}
Application
package obs;
public class Application {
public static void main(String[] args) { ---- Changement d'atat -----
// Création du sujet ---- Changement d'atat -----
ObservableImpl observable=new ObservableImpl(); Observer 1 a reçu la nouvelle valeur de état :90
// Création des observateurs Observer 2 Mise à jour avec état:90
---- Changement
ObserverImpl1 o1=new ObserverImpl1(); ObserverImpl2 o2=new d'atat -----
ObserverImpl2();
// Changer l'état du sujet Observer 2 Mise à jour avec état:23
System.out.println("---- Changement d'atat -----");
observable.setEtat(70);
// Enregistrer les observateur
observable.addObserver(o1); observable.addObserver(o2);
// Changer l'état du sujet
System.out.println("---- Changement d'atat -----");
observable.setEtat(90);
// Supprimer un observateur
observable.removeObsever(o1);
//Changer l'état du sujet
System.out.println("---- Changement d'atat -----");
observable.setEtat(23);
}
}
Application
Cahier des charges
Félicitation! Votre société a été retenue pour construire notre station météorologique de dernière génération
consultable en ligne!
La station sera basée sur notre objet DonneesMeteo (brevet en cours),qui enregistre les conditions météorologique
à un moment donné (température, hygrométrie et pression atmosphérique).
Nous aimerions que vous nous créiez une application qui fournira d’abord trois affichages: conditions actuelles,
statistiques et prévisions simples, tous trois mis à jour en temps réel au fur et à mesure que l’objet DonneesMeteo acquiert les
données les plus récentes.
De plus cette station météo doit être extensible. MétéoExpress veut commercialiser une API pour que les autres
développeurs puissent réaliser leurs propres affichages et les insérer directement. Nous souhaitons que vous nous fournissiez
cette API !
MétéoExpress est convaincu d’avoir un excellent modèle métier: une fois les clients acrochés, nous prévoyons de
les facturer pour chaque affichage qu’ils utilisent.
Le meilleur est pour la fin : vous serez payé en stock options.
Nous attendons avec impatience vos documents de conception et votre première version alpha
Cordialement,
Jean-Loup Ragan, PDG MétéoExpress
P.S. Nous vous envoyons par chrono les fichiers source de DonnesMeteo
Vue d’ensemble de l’application
Les trois composants du système sont:
• La station météo : Équipement physique qui recueille les données météo sur le temps.
• L’affichage lui-même que les utilisateurs consultent pour connaître les conditions
météorologiques actuelles.
Capteur Extrait
d’humidité Les données Affiche
:DonneesMeteo Temp: 22°
Capteur de Hygro : 60
Station météo Pression :
température
Capteur de
pression Objet DonneesMeteo
Dispositif a’affichage
Ce que MétéoExpress Fournit Ce que nous implémentons
Si nous choisissons de l’accepter, notre tâche consiste à créer une application
qui utilise l’objet DonneesMeteo qui actualise ces trois affichages: conditions
actuelles, statistiques et prévisions
A l’intérieur de la classe DonneesMeteo
Le lendemain matin, les fichiers source de DonneesMeteo arrivent
comme promis.
La méthode actualiserMesures() est appelée chaque fois qu’une nouvelle mesure est disponible. Nous ne savons pas comment cette
méthode est appelée, et peu importe.
Nous devrons implémenter trois affichages qui utilisent les données météorologiques:
• Un affichage des conditions actuelles
Ces trois affichages doivent être mis à jour, chaque fois que DonnesMeteo aquiert de nouvelles données.
• Les utilisateurs pourront ajouter ou retirer autant d ’éléments qu’ils le souhaitaient à l’application
• Conditions actuelles
• Statistiques
• prévisions
Premier essai de station météo
Voici une première possibilité d’implémentation: nous suivons l’indication des développeurs de
MeteoExpress et nous ajoutons notre code à la méthode actualiderMesures():
Au moins, nous semblons utiliser une interface commune pour Points de variation : nous devons
communiquer avec les affichages.. Ils ont tous une méthode l’encapsuler
actualier() qui lie les valeurs de temp, humidité et pression
Faites connaissance avec le pattern Observateur
Vous savez comment fonctionne un abonnement à un magazine:
1. Un éditeur se lance dans les affaires et commence à diffuser des magazines
2. vous souscrivez un abonnement
3. Chaque fois qu’il y’a une nouvelle édition, vous la recevez. Et tant que vous
êtes abonné, vous recevez les nouvelles éditions.
4. Quand vous ne vouliez pas de ces magazines, vous résiliez votre
abonnement. On cesse alors de vous les livrer.
5. Tant que l’éditeur reste en activité, les particuliers, les hôtels, les
compagnies aériennes, etc., ne cessent de s’abonner et de se désabonner.
2 Objet Chien
Donée=2
2
2
Objet Sujet:
Objet Chat
Gère une donnée quelconque
Objet Souris
Cet objet n’est pas un
observateur : il n’est pas
informés quand les données du Les observateurs ont souscrit un abonnement (
Objet Canard sujet changent se sont enregistrés) au près du sujet pour
recevoir les mises à jour quand les données du
sujet changent. Ils peuvent eux-mêmes se
désabonner.
Pattern Observateur : définition
sujet observateurs
1 * Les observateurs
Un sujet concret concrets peuvent être
implémente toujours n’importe quelle classe
l’interface Sujet. qui implémente
Outre les méthode d’ajout l’interface Observateur.
et de suppression Chaque observateur
d’observateurs, le sujet s’enregistre au près du
concret implémente la Le sujet concret peut
également avoir des sujet réel pour recevoir
méthode les mises à jour;
notifierObservateurs() qui méthodes pour accéder
sert à mettre à jour tous à son état (getEtat()) et le
les observateurs chaque modifier (setEtat())
fois que l’état change.
Le pouvoir du faible couplage
Lorsque deux objets sont faiblement couplés, ils peuvent interagir sans pratiquement se connaître.
Le pattern observateur permet une conception dans laquelle le couplage entre sujet et observateurs est faible:
• Le sujet ne sait qu’une seule chose :
• L’observateur implémente une certaine interface (Observateur).
• Il n’a pas donc besoin de connaître ni la classe concrète de l’observateur, ni ce qu’il fait ni quoi que ce soit d’autre.
• Nous pouvons ajouter des observateurs à tout moment :
• Comme le sujet dépend uniquement d’une liste d’objets qui implémente l’interface Observateur (observateurs:ArrayList), nous pouvons
ajouter, supprimer, modifier des observateurs à volonté pendant l’exécution.
• Le sujet continue de fonctionner comme si rien n’était
• Nous n’avons jamais besoin de modifier le sujet pour ajouter de nouveaux types d’observateurs :
• Disons qu’une nouvelle classe concrète se présente et a besoin d’être un observateur, nous n’avons besoin d’ajouter quoi que ce soit au
sujet pour gérer ce nouveau type.
• Il suffit qu’elle implémente l’interface Observateur, et de l’enregistrer entant que observateur.
• Le sujet continue de diffuser des notifications à tous les observateurs.
• Nous pouvons réutiliser les observateurs et les sujets indépendamment les uns des autres.
• Si nous avons un autre emploi d’un sujet ou d’un observateur, nous pouvons les réutiliser sans problème par ce qu’ils sont faiblement
couplés.
• Les modifications des sujets n’affectent pas les observateurs et inversement
Le pouvoir du faible couplage
Principe de conception:
• S’il vous faut un peu d’aide, lisez la page suivante : vos collègues sont déjà entrain de penser à la
conception de la station météo.
Conversation dans un box
Marie: Et bien, ça aide de savoir que nous utilisons le pattern Observateur.
Anne: Oui… mais comment allons nous l’appliquer.
Marie : regardons à nouveau la définition :
• Le pattern observateur définit une relation entre les objets de type un à plusieurs, de façon que,
lorsqu’un objet change d’état, tous ce qui en dépendent en soient informés et soient mis à jour
automatiquement
Marie : ça a l’air claire quand on y pense : Notre classe DonneesMeteo est le « un », et le « plusieurs », ce sont les éléments qui affichent les
différentes mesures;
Anne : c’est vrai, la classe DonneesMeteo a avidement un état… la température, l’humidité, la pression atmosphérique, et bien sûr, ces données
changent.
Marie : Oui, et quand ces données changent, il faut notifier les éléments d’affichage pour qu’ils puissent mettre à jour l’affichage en utilisant
les nouvelles mesures.
Anne : super, maintenant je crois que je vois comment appliquer le pattern Observateur à notre problème.
Marie : mais il y’a encore deux ou trois choses que je ne suis pas sûre d’avoir comprises.
Anne : Pae exemple ?
Marie : D’abord, comment faire pour que les éléments d’affichage puissent obtenir les mesures.
Conversation dans un box
Anne: Eh bien, en regardant à nouveau le diagramme de classes du pattern Observateur, si nous faisons de
l’objet DonneesMeteo le sujet et des éléments d’affichage les observateurs, alors les affichages vont
s’enregistrer eux-mêmes auprès de l’objet DonneesMeteo pour obtenir les informations dont ils auront
besoin, non ?
Marie: Oui… et une fois que la station météo est au courant de l’existence d’un élément d’affichage, elle
peut simplement appeler une méthode pour lui transmettre les mesures.
Anne: Il faut se souvenir que chaque affichage peut être différent… et c’est là que je crois que qu’intervient
une interface commune. Même si, chaque composant est d’un type différent, ils doivent implémenter tous une
même interface pour que l’objet DonneesMeteo sache comment leur transmettre les mesures.
Marie: je vois ce que tu veux dire. Chaque affichage aura par exemple une méthode actualier() que
DonneesMeteo va appeler.
Anne: Et actualiser() est définie dans une inteface commune que tous les éléments d’affichage
implémenteront.
Concevoir la station météo Tous nos composants implémentent
Tous les affichages possèdent
la méthode afficher(). Il
Voici l’interface Sujet l’interface Observateur. Ainsi le
implémentent donc cette
sujet dispose d’une interface à qui
interface
parler quand le moment est venu.
observateurs
sujet
dm:DonneesMeteo
public class TestDonneesMeteo { temp=22
public static void main(String[] args) { hum=65 ac:AffConditions
press=1020 temp=22
DonneesMeteo dm=new DonneesMeteo();
Observateurs: hum=65
AffichageConditions ac=new AffichageConditions(dm);
sujet:
dm.setMesures(22,65,1020);
dm.setMesures(25,75,1000); aa:AutreAffichage
dm.setMesures(23,30,1800); temp=22
} press=1020
sujet:
}
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Classification GOF des Design Patterns
Pattern Décorateur
Catégorie :
• Structure
Résultat :
med@youssfi.net
Implémentation
ComposantAbstrait.java :
public interface ComposantAbstrait {
public void operation();
}
ComposantConcretImpl1.java :
public class ComposantConcretImpl1 implements ComposantAbstrait {
@Override
public void operation() {
System.out.println("Je sais faire uniquement ça Version 1");
}
}
ComposantConcretImpl2.java :
public class ComposantConcretImpl2 implements ComposantAbstrait {
@Override
public void operation() {
System.out.println("Je sais faire uniquement ça Version 2");
}
}
Implémentation
DecorateurAbstrait.java :
public abstract class DecorateurAbstrait implements ComposantAbstrait {
protected ComposantAbstrait composantAbstrait;
public DecorateurAbstrait(ComposantAbstrait composantAbstrait) {
super();
this.composantAbstrait = composantAbstrait;
}
}
DecorateurConcretImpl1.java :
public class DecorateurConcretImpl1 extends DecorateurAbstrait {
public DecorateurConcretImpl1(ComposantAbstrait composantAbstrait) {
super(composantAbstrait);
}
@Override
public void operation() {
System.out.println("Décorateur 1 : avant, je je fais X");
composantAbstrait.operation();
System.out.println("Décorateur 1 : après, je je fais Y");
}
}
Implémentation
DecorateurConcretImpl2.java :
med@youssfi.net
Utilisation du pattern Décorateur
ComposantAbstrait c=new ComposantConcretImpl1();
c.operation();
c :ComposantConcretImpl1
c=new DecorateurConcretImpl1(c);
c.operation();
c :DecorateurConcretImpl1 :ComposantConcretImpl1
c=new DecorateurConcretImpl2(c);
c.operation();
c :DecorateurConcretImpl2 :DecorateurConcretImpl1
:ComposantConcretImpl1
Utilisation du pattern Décorateur
public class Application {
public static void main(String[] args) {
ComposantAbstrait composantAbstrait=new ComposantConcretImpl1();
composantAbstrait.operation();
System.out.println("--------------------"); System.out.println("Première décoration");
System.out.println("--------------------");
composantAbstrait=new DecorateurConcretImpl1(composantAbstrait);
composantAbstrait.operation();
System.out.println("--------------------"); System.out.println("Deuxième décoration");
System.out.println("--------------------");
composantAbstrait=new DecorateurConcretImpl2(composantAbstrait);
composantAbstrait.operation();
}} Je sais faire uniquement ça Version1
--------------------
Première décoration
--------------------
Décorateur 1 : avant, je je fais X
Je sais faire uniquement ça Version1
Décorateur 1 : après, je je fais Y
--------------------
Deuxième décoration
--------------------
Décorateur 2 : avant, je je fais A
Décorateur 1 : avant, je je fais X
Je sais faire uniquement ça Version1
Décorateur 1 : après, med@youssfi.net
je je fais Y
Décorateur 2 : après, je je fais B
Application
med@youssfi.net
Bienvenue chez StarbuzzCoffee
Starbuzz Coffee s’est fait un nom en devenant la plus importante chaîne de « salons de café »
aux états unis.
Quand ils ont commencé, ils on conçu leurs classes comme ceci:
Boisson
Et bien!
description
Voila ce que l’on appelle
getDescription()
« une explosion combinatoire »
cout()
// autres méthodes
ColombiaChocolat EspressoLaitCaramml
ColombiaLaitChocolatCaramel EspressoLaitChocolatEspresso
cout() cout() EspressoEspressoChantilly
cout()
SumatraLaitChocolat cout() cout()
cout() cout()
SumatraLaitCaramelChantilly
SumatraLaitCaramelChantilly
SumatraLaitCaramelChantilly
SumatraLaitCaramelChantilly
SumatraLaitCaramelChantilly
cout()
Chaque méthode cout() calcule le
cout()
cout()cout() coût du café plus celui des
cout()cout()
ingrédients de la commande
Une proposition pour éviter l’explosion de classes
Boisson
description:String
lait:boolean
caramel:boolean
chocolat:boolean
chantilly:boolean
getDescription()
cout() // non
abstraite
// autres méthodes
Notre but est de permettre d’étendre facilement les classes pour incorporer
de nouveaux comportements sans modifier le code existant.
:Sumatra
b1
cout()
:Chocolat :Sumatra
b1
cout() cout()
DecorateurIngredient
getDescription()
Colombia Sumatra
Espresso Deca
cout() cout()
cout() cout()
Et voici nos décorateurs pour les ingrédients remarquez qu’ils implémentent cout() et getDescription()
Implémentation de Starbuzz
Boisson.java
public abstract class Boisson {
String description;
DecorateurIngredient.java
public abstract class DecorateurIngredient extends Boisson {
protected Boisson boisson;
public DecorateurIngredient(Boisson boisson) {
this.boisson = boisson;
}
public abstract String getDescription();
}
Coder les boissons
Espresso.java
public class Espresso extends Boisson {
public Espresso(){
description="Espresso";
}
public double cout() {
return 1.99;
}
}
Columbia.java
public class Colombia extends Boisson {
public Colombia(){
description="Colombia";
}
public double cout() {
return .89;
}
}
Coder les ingrédients (Décorateurs)
Chocolat.java
public class Chocolat extends DecorateurIngredient {
public Chocolat(Boisson boisson) { super(boisson); }
public double cout() { return 0.20 +boisson.cout() ;
}
public String getDescription() {
return boisson.getDescription()+", Chocolat";
}
}
Caramel.java
public class Caramel extends DecorateurIngredient {
public Caramel(Boisson boisson) { super(boisson); }
public double cout() { return 0.22 +boisson.cout() ; }
public String getDescription() {
return boisson.getDescription()+", Caramel";
}
}
Le café est servi
Nous souhaitons créer un décorateur de InputStream qui nous permet de décrypter un fichier qui contient une suite de nombres paires.
Le décryptage consiste à récupérer du fichiers deux nombre par deux nombres en faisant la différence entre les deux.
• Exemple : Si le fichier contient le texte : bacadb
• Le nombre décrypté est obtenu comme suit:
• code ascii (b)-code ascii(a) = 1
• code ascii (c)-code ascii(a) = 2
• code ascii (d)-code ascii(b) = 2
• Le nombre décrypté est 122.
• Pour créer l’objet DecrypteInputStream, on peut écrire
• is=new DecrypteurInputStream(is);
• Pour lire un nombre décrypté
• int c=is.read();
Travail à faire
1. Créer un diagramme de classes
2. Créer un décorateur abstrait de InpuStream : DecorateurInputStream.java
3. Créer un Décorateur concret de InputStream, qui permet de décrypter un InputStream :
DecrypteInputStream.java
4. Créer un fichier texte « original.txt » qui contient le texte crypté
5. Créer une application qui permet de:
a. Créer un FileInputStream représentant le fichier « Original.txt »
b. Décorer l’objet créé par un objet de DecrypteInputStream
c. Afficher le texte décrypté
Design Patterns Par : Mohamed YOUSSFI
Lab. SSDIA, ENSET Mohammedia,
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Design Patterns du GoF (Gang of Four ) (Gamma, Helm, Johnson, Vlissides)
Pattern Composite
Catégorie :
• Structure
Objectif du pattern Composite
• Organiser les objets en structure arborescente afin de représenter une hiérarchie.
• Permettre à la partie cliente de manipuler un objet unique et un objet composé de la
même manière.
Résultat :
• Le Design Pattern permet d'isoler l'appartenance à un agrégat.
Pattern Composite
Exemples
• Un dossier peut contenir des fichiers ou des
dossiers
• Un Menu contient des éléments de menus ou
d’autres sous menus
Exemples
• Un élément HTML est formé par des attributs et
d’autres éléments
• Une forme peut être soit un rectangle, un cercle,
une ligne ou un groupe de formes
Raison d’utilisation
• Element :
• implémente un objet de l'arborescence n'ayant pas d'objet le composant.
• Composite :
• implémente un objet de l'arborescence ayant un ou des objets le composant.
• La partie client manipule les objets par l'interface Composant.
Implémentation
/* Composant.java */ public abstract class Composant {
protected String nom;
protected int level;
public Composant(String nom) {
this.nom = nom;
}
public abstract void operation();
}
:Composite
/* Application.java */ nom="composite 2"
public class Application { level= 1
public static void main(String[] args) {
:Element
Composite racine=new Composite("Composite 1"); nom="Elément 21"
Composite composite2=new Composite("Composite 2"); level= 2
racine.add(composite2);
:Element
racine.add(new Element("Elément 11"));
nom="Elément 22"
racine.add(new Element("Elément 12")); level= 2
racine.add(new Element("Elément 13"));
composite2.add(new Element("Elément 21")); :Element
nom="Elément 11"
composite2.add(new Element("Elément 22"));
level= 1
racine.operation();
}} :Element
Opération sur un composite(Composite 1)
-- Opération sur un composite(Composite 2) nom="Elément 12"
---- Opération sur l'élément (Elément 21) level= 1
---- Opération sur l'élément (Elément 22)
-- Opération sur l'élément (Elément 11)
-- Opération sur l'élément (Elément 12)
:Element
-- Opération sur l'élément (Elément 13) nom="Elément 13"
med@youssfi.net level= 1
Design Patterns Par : Mohamed YOUSSFI
Lab. SSDIA, ENSET Mohammedia,
Pattern Adapter Université Hassan II de Casablanca Maroc
med@youssfi.net
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Exemple d’implémentation du Design pattern Adapter :
Brancher un ordinateur avec interface HDMI avec un vidéo projecteur avec interface VGA
Mohamed YOUSSFI, Lab. Informatique, Intelligence Artificielle et Cyber sécurité, ENSET, Université Hassan II de Casablancamed@youssfi.net
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Pattern Adapter
Catégorie :
• Structure
Objectif du pattern
• Convertir l'interface d'une classe dans une autre interface comprise par la partie cliente.
• Permettre à des classes de fonctionner ensemble, ce qui n'aurait pas été possible à cause de
leurs interfaces incompatibles.
Résultat :
• Le Design Pattern permet d'isoler l'adaptation d'un sous-système.
Diagramme de classes
med@youssfi.net
Raison d’utilisation
• Le système doit intégrer un sous-système existant.
• Ce sous-système a une interface non standard par rapport au système.
• Cela peut être le cas d'un driver bas niveau pour de l'informatique
embarquée.
• Le driver fournit par le fabricant ne correspond pas à l'interface utilisée par le
système pour d'autres drivers.
• La solution est de masquer cette interface non stantard au système et de lui
présenter une interface standard.
• La partie cliente utilise les méthodes de l'Adaptateur qui utilise les méthodes
du sous-système pour réaliser les opérations correspondantes.
med@youssfi.net
Responsabilités
• Standard : définit une interface qui est identifiée comme standard dans la partie cliente.
• ImplStandard : implémente l'interface Standard. Cette classe n'a pas besoin d'être adaptée.
• ImplAdaptee : permet de réaliser les fonctionnalités définies dans l'interface Standard,
mais ne la respecte pas. Cette classe a besoin d'être adaptée.
• Adaptateur : adapte l'implémentation ImplAdaptee à l'interface Standard. Pour réaliser
l'adaptation, l'Adaptateur peut utiliser une ou plusieurs méthodes différentes de
l'implémentation ImplAdaptee pour réaliser l'implémentation de chaque méthode de
l'interface Standard.
• La partie cliente : manipule des objets Standard. donc, l'adaptation est transparente pour
la partie cliente.
med@youssfi.net
Implémentation
/* Standard.java */
public interface Standard {
public void operation(int nb1,int nb2);
}
/* ImplStandard.java */
public class ImplStandard implements Standard {
@Override
public void operation(int nb1, int nb2) {
System.out.println("Standard, Résultat est :"+nb1*nb2); /* ImplStandard.java */
}
}
public class ImplAdaptee {
public int operation2(int nb1,int nb2){
return nb1*nb2;
}
public void operation3(int nb){
System.out.println("Adaptée, Résultat="+nb);
}
} med@youssfi.net
Implémentation
/* AdaptateurHeritage.java */
public class AdaptateurHeritage extends ImplAdaptee implements Standard {
@Override
public void operation(int nb1, int nb2) {
int nb=operation2(nb1, nb2);
operation3(nb);
}
}
/* AdaptateurComposition.java */
public class AdaptateurComposition implements Standard {
private ImplAdaptee adaptee=new ImplAdaptee();
@Override
public void operation(int nb1, int nb2) {
int nb=adaptee.operation2(nb1, nb2);
adaptee.operation3(nb);
}
}
Implémentation
/* Application.java */
public class Application {
public static void main(String[] args) {
Standard standard=new ImplStandard();
standard.operation(7, 9);
Standard adaptee1=new AdaptateurHeritage();
adaptee1.operation(7, 9);
Standard adaptee2=new AdaptateurComposition();
adaptee2.operation(7, 9);
Standard, Résultat est :63
}
Adaptée, Résultat=63
} Adaptée, Résultat=63
med@youssfi.net
Design Patterns Par : Mohamed YOUSSFI
Lab. SSDIA, ENSET Mohammedia,
Pattern Proxy Université Hassan II de Casablanca Maroc
med@youssfi.net
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Design Patterns du GoF (Gang of Four ) (Gamma, Helm, Johnson, Vlissides)
Pattern Proxy
Catégorie :
• Structure
Objectif du pattern
• Fournir un intermédiaire entre la partie cliente et un objet pour contrôler les accès à ce
dernier.
Résultat :
• Le Design Pattern permet d'isoler le comportement lors de l'accès à un
objet.
Pattern Proxy
med@youssfi.net
Raison d’utilisation
• Les opérations d'un objet sont coûteuses en temps ou sont soumises à une
gestion de droits d'accès.
• Il est nécessaire de contrôler l'accès à un objet.
• Cela peut être un système de chargement d'un document. Le document est
très lourd à charger en mémoire ou il faut certaines habilitations pour
accéder à ce document.
• L'objet réel (système de chargement classique) est l'implémentation.
L'intermédiaire entre l'implémentation et la partie cliente est le proxy.
• Le proxy fournit la même interface que l'implémentation. Mais il ne charge
le document qu'en cas de réel besoin (pour l'affichage par exemple) ou
n'autorise l'accès que si les conditions sont satisfaites.
med@youssfi.net
Responsabilités
• Abstraction : définit l'interface des classes Implémentation et Proxy.
• Implémentation : implémente l'interface. Cette classe définit l'objet que l'objet Proxy
représente.
• Proxy : fournit un intermédiaire entre la partie cliente et l'objet Implémentation. Cet
intermédiaire peut avoir plusieurs buts (synchronisation, contrôle d'accès, cache, accès
distant, ...). Dans l'exemple, la classe Proxy n'instancie un objet Implémentation qu'en cas de
besoin pour appeler la méthode correspondante de la classe Implémentation.
• La partie cliente appelle la méthode operation() de l'objet Proxy.
Implémentation
/* Abstraction.java */ /* Implemantation.java */
public interface Abstraction { public class Implementation implements Abstraction {
@Override
public void operation(); public void operation() {
} System.out.println("Exécution de l'opération de
l'implémentation...");
}}
/* Proxy.java */
med@youssfi.net
Implémentation
/* Application.java */
public class Client { :Client
Créer
public static void main(String[] args) { :Proxy
Abstraction proxy=new Proxy(); operation
Vérification
proxy.operation();
Créer :Implémentation
}}
operation
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Design Patterns du GoF (Gang of Four ) (Gamma, Helm, Johnson, Vlissides)
Pattern Template Method
Catégorie :
• Comportement
Objectif du pattern
• Définir le squelette d'un algorithme en déléguant certaines étapes à des sous-classes.
Résultat :
• Le Design Pattern permet d'isoler les parties variables d'un algorithme.
Raisons d’utilisation :
• Une classe possède un fonctionnement global, mais les détails de son algorithme doivent être
spécifiques à ses sous-classes.
Responsabilités
• TemplateClass: définit des méthodes abstraites primitives. La classe implémente le squelette
d'un algorithme qui appelle les méthodes primitives.
• Implentation1, Implementation2 : sont des sous-classes concrète de TemplateClass. Elle
implémente les méthodes utilisées par l'algorithme de la méthode operationTemplate() de
TemplateClass.
• La partie cliente appelle la méthode de TemplateClass qui définit l'algorithme.
Design pattern Template Method
110
Implémentation
/* TemplateClass.java */ /* Implementation1.java */
package tm; package tm;
public abstract class TemplateClass { public class Implementation1 extends TemplateClass {
public int operationTemplate(){ @Override
int a=operationAbs1(); protected int operationAbs1() {
int somme=0; return 8;
for(int i=0;i<a;i++){ }
somme+=operationAbs2(); @Override
} protected int operationAbs2() {
return somme; return 12;
} }
protected abstract int operationAbs1(); }
protected abstract int operationAbs2();
}
Implémentation
/* TemplateClass.java */ /* Implementation1.java */
package tm; package tm;
public abstract class TemplateClass { public class Implementation2 extends TemplateClass {
public int operationTemplate(){ @Override
int a=operationAbs1(); protected int operationAbs1() {
int somme=0; return 90;
for(int i=0;i<a;i++){ }
somme+=operationAbs2(); @Override
} protected int operationAbs2() {
return somme; return 33;
} }
protected abstract int operationAbs1(); }
protected abstract int operationAbs2();
}
Implémentation
import tm.Implementation1;
import tm.Implementation2;
import tm.TemplateClass;
System.out.println(t1.operationTemplate());
t1=new Implementation2();
System.out.println(t1.operationTemplate());
}
Design Patterns Par : Mohamed YOUSSFI
Lab. SSDIA, ENSET Mohammedia,
Pattern State Université Hassan II de Casablanca Maroc
med@youssfi.net
Strategy
Template
Singleton
Method
Design
Adapter Patterns Composite
GOF
Mediator Decorator
Proxy
Pattern State
Catégorie :
• Comportement
Objectif du pattern
• Changer le comportement d'un objet selon son état interne.
Résultat :
• Le Design Pattern permet d'isoler les algorithmes propres à chaque état
d'un objet.
med@youssfi.net
Exemple de problème
116
Design pattern Etat ou State
Le pattern Etat permet de déléguer le comportement d'un objet dans un autre objet. Cela permet de changer le
comportement de l'objet en cours d'exécution et de simuler un changement de classe.
117
Raison d’utilisation
• Un objet a un fonctionnement différent selon son état interne. Son état change selon les
méthodes appelées.
• Cela peut être un document informatique. Il a comme fonctions ouvrir, modifier, sauvegarder
ou fermer. Le
• comportement de ces méthodes change selon l'état du document.
• Les différents états internes sont chacun représenté par une classe état (ouvert, modifié,
sauvegardé et fermé).
• Les états possèdent des méthodes permettant de réaliser les opérations et de changer d'état
(ouvrir, modifier,sauvegarder et fermer). Certains états bloquent certaines opérations (modifier
dans l'état fermé).
• L'objet avec état maintient une référence vers l'état actuel. Il présente les opérations à la partie
cliente.
med@youssfi.net
Responsabilités
• ClasseAvecEtat : est une classe avec état. Son comportement change en fonction de
son état. La partie changeante de son comportement est déléguée à un objet Etat.
• EtatA, EtatB et EtatC : sont des sous-classes concrètes de l'interface Etat. Elles
implémentent des méthodes qui sont associées à un Etat.
med@youssfi.net
Diagramme d’état transition
Implémentation
/* Etat.java */
public abstract class Etat {
protected ClasseAvecEtat classeAvecEtat;
public Etat(ClasseAvecEtat classeAvecEtat) {
this.classeAvecEtat = classeAvecEtat;
}
public abstract void operationEtatA();
public abstract void operationEtatB();
public abstract void operationEtatC();
/* ClasseAvecEtat.java */
public class ClasseAvecEtat {
private Etat etat;
public ClasseAvecEtat() { etat=new EtatA(this); }
public void operationEtatA() { etat.operationEtatA();}
public void operationEtatB() { etat.operationEtatB(); }
public void operationEtatC() { etat.operationEtatC(); }
public void doAction() { etat.doAction(); }
public Etat getEtat() { return etat; }
public void setEtat(Etat etat) { this.etat = etat; }
}
med@youssfi.net
Implémentation
/* EtatA.java */
public class EtatA extends Etat{
public EtatA(ClasseAvecEtat classeAvecEtat) {super(classeAvecEtat); }
@Override
public void operationEtatA() {
System.out.println("Classe déjà dans l'état A");
}
@Override
public void operationEtatB() {
classeAvecEtat.setEtat(new EtatB(classeAvecEtat));
System.out.println("Changement d'état de A=>B");
}
@Override
public void operationEtatC() {
System.out.println("Impossible de passer de A =>C");
}
@Override
public void doAction() { System.out.println("Etat courant : A"); }
}
Implémentation
/* EtatB.java */
public class EtatB extends Etat{
public EtatB(ClasseAvecEtat classeAvecEtat) { super(classeAvecEtat);}
@Override
public void operationEtatA() {
System.out.println("Pas de possible de passer de B vers A");
}
@Override
public void operationEtatB() {
System.out.println("Déjà dans l'état B");
}
@Override
public void operationEtatC() {
classeAvecEtat.setEtat(new EtatC(classeAvecEtat));
System.out.println("Changement d'état de B vers C");
}
@Override
public void doAction() { System.out.println("Etat courant : B"); }
}
Implémentation
/* EtatC.java */
public class EtatC extends Etat{
public EtatC(ClasseAvecEtat classeAvecEtat) { super(classeAvecEtat); }
@Override
public void operationEtatA() {
System.out.println("Changement d'état de C vers A");
classeAvecEtat.setEtat(new EtatA(classeAvecEtat));
}
@Override
public void operationEtatB() {
System.out.println("Changement d'état de C vers B");
classeAvecEtat.setEtat(new EtatB(classeAvecEtat));
}
@Override
public void operationEtatC() {
System.out.println("Déjà dans l'état C");
}
@Override
public void doAction() { System.out.println("Etat courant : C"); }
}
Implémentation
/* Application.java */