Design Patterns
Part 8
Mohamed Youssfi
Laboratoire Signaux Systèmes Distribués et Intelligence Artificielle (SSDIA)
ENSET, Université Hassan II Casablanca, Maroc
Email : med@[Link]
Supports de cours : [Link]
Chaîne vidéo : [Link]
Recherche : [Link]
med@[Link]
Patterns :
- Stat
- Template Method
- Command
- Mediator
Pattern Stat
Le comportement des méthodes d'un objet
dépendent souvent de l‘état de celui-ci.
Cet état est en général représente par les
attributs de l'objet.
Cependant, plus l'objet peut prendre d‘états
comportementaux distincts, plus la
structuration de l'objet est complexe.
Le design pattern "état" est la meilleure
solution pour bien structurer et représenter
les différents états d'un objet ainsi que les
transitions entre ces états sous une forme
orientée objet.
med@[Link]
Exemple de problème
• Un avion peut être dans l'un des trois états suivants :
• soit dans le garage,
• soit sur la piste,
• soit en l'air.
• Lorsqu'il est dans le garage, la méthode sortirDuGarage permet de
passer dans l‘état "sur la piste" .
• Lorsqu'il est sur la piste, la méthode entrerAuGarage permet de passer
dans l‘état "dans le garage"
• La méthode décoller permet de passer dans l‘état "en l'air".
• Lorsqu'il est en l'air, la méthode atterrir permet de passer dans l‘état "sur
la piste".
• Les autres combinaisons Etats - Méthodes génèrent une erreur comme par
exemple, invoquer décoller lorsque l'avion est dans le garage.
4
Pattern Stat
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@[Link]
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.
6
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@[Link]
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.
Etat : définit l'interface d'un comportement d'un état.
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@[Link]
Diagramme d’état transition
med@[Link]
Implémentation
/* [Link] */
public abstract class Etat {
protected ClasseAvecEtat classeAvecEtat;
public Etat(ClasseAvecEtat classeAvecEtat) {
[Link] = classeAvecEtat;
}
public abstract void operationEtatA();
public abstract void operationEtatB();
public abstract void operationEtatC();
public abstract void doAction();
}
med@[Link]
Implémentation
/* [Link] */
public class ClasseAvecEtat {
private Etat etat;
public ClasseAvecEtat() { etat=new EtatA(this); }
public void operationEtatA() { [Link]();}
public void operationEtatB() { [Link](); }
public void operationEtatC() { [Link](); }
public void doAction() { [Link](); }
public Etat getEtat() { return etat; }
public void setEtat(Etat etat) { [Link] = etat; }
}
med@[Link]
Implémentation
/* [Link] */
public class EtatA extends Etat{
public EtatA(ClasseAvecEtat classeAvecEtat) {super(classeAvecEtat); }
@Override
public void operationEtatA() {
[Link]("Classe déjà dans l'état A");
}
@Override
public void operationEtatB() {
[Link](new EtatB(classeAvecEtat));
[Link]("Changement d'état de A=>B");
}
@Override
public void operationEtatC() {
[Link]("Impossible de passer de A =>C");
}
@Override
public void doAction() { [Link]("Etat courant : A"); }
}
med@[Link]
Implémentation
/* [Link] */
public class EtatB extends Etat{
public EtatB(ClasseAvecEtat classeAvecEtat) { super(classeAvecEtat);}
@Override
public void operationEtatA() {
[Link]("Pas de possible de passer de B vers A");
}
@Override
public void operationEtatB() {
[Link]("Déjà dans l'état B");
}
@Override
public void operationEtatC() {
[Link](new EtatC(classeAvecEtat));
[Link]("Changement d'état de B vers C");
}
@Override
public void doAction() { [Link]("Etat courant : B"); }
}
med@[Link]
Implémentation
/* [Link] */
public class EtatC extends Etat{
public EtatC(ClasseAvecEtat classeAvecEtat) { super(classeAvecEtat); }
@Override
public void operationEtatA() {
[Link]("Changement d'état de C vers A");
[Link](new EtatA(classeAvecEtat));
}
@Override
public void operationEtatB() {
[Link]("Changement d'état de C vers B");
[Link](new EtatB(classeAvecEtat));
}
@Override
public void operationEtatC() {
[Link]("Déjà dans l'état C");
}
@Override
public void doAction() { [Link]("Etat courant : C"); }
}
Implémentation
/* [Link] */
public class Application {
public static void main(String[] args) {
ClasseAvecEtat obj=new ClasseAvecEtat(); [Link]();
[Link]("-------------");
[Link](); [Link]();[Link]("-------------");
[Link](); [Link]();[Link]("-------------");
[Link](); [Link]();[Link]("-------------");
[Link](); [Link]();[Link]("-------------");
[Link](); [Link]();[Link]("-------------");
}
}
Etat courant : A Changement d'état de A=>B
------------- Etat courant : B
Classe déjà dans l'état A -------------
Etat courant : A Changement d'état de B vers C
------------- Etat courant : C
Impossible de passer de A =>C -------------
Etat courant : A Changement d'état de C vers A
------------- Etat courant : A
-------------
Pattern
Template Method
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.
med@[Link]
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.
med@[Link]
Design pattern Template Method
19
Implémentation
/* [Link] */
package tm;
public abstract class TemplateClass {
public int operationTemplate(){
int a=operationAbs1();
int somme=0;
for(int i=0;i<a;i++){
somme+=operationAbs2();
}
return somme;
}
protected abstract int operationAbs1();
protected abstract int operationAbs2();
}
med@[Link]
Implémentation
/* [Link] */
package tm;
public class Implementation1 extends TemplateClass {
@Override
protected int operationAbs1() {
return 8;
}
@Override
protected int operationAbs2() {
return 12;
}
}
med@[Link]
Implémentation
/* [Link] */
package tm;
public class Implementation2 extends TemplateClass{
@Override
protected int operationAbs1() {
return 34;
}
@Override
protected int operationAbs2() {
// TODO Auto-generated method stub
return 56;
}
}
med@[Link]
Implémentation
/* [Link] */
import tm.Implementation1;
import tm.Implementation2;
import [Link];
public class Application {
public static void main(String[] args) {
TemplateClass t1=new Implementation1();
[Link]([Link]());
t1=new Implementation2();
[Link]([Link]());
}
}
96
1904
med@[Link]
Pattern
Command
Pattern Command
Catégorie :
◦ Comportement
Objectif du pattern
◦ Encapsuler une requête sous la forme d' objet.
◦ Paramétrer facilement des requêtes diverses.
◦ Permettre des opérations réversibles.
Résultat :
◦ Le Design Pattern permet d'isoler une
requête.
med@[Link]
Pattern Command
Raison d’utilisation :
◦ Le système doit traiter des requêtes. Ces requêtes peuvent
provenir de plusieurs émetteurs.
◦ Plusieurs émetteurs peuvent produire la même requête.
◦ Les requêtes doivent pouvoir être annulées.
◦ Cela peut être le cas d'une IHM avec des boutons de commande,
des raccourcis clavier et des choix de menu aboutissant à la
même requête.
◦ La requête est encapsulée dans un objet : la commande.
◦ Chaque commande possède un objet qui traitera la requête : le
récepteur.
◦ La commande ne réalise pas le traitement, elle est juste porteuse
de la requête.
◦ Les émetteurs potentiels de la requête (éléments de l'IHM) sont
des invoqueurs.
◦ Plusieurs invoqueurs peuvent se partager la même commande.
med@[Link]
Responsabilités
Commande : définit l'interface d'une
commande.
CommandeA et CommandeB : implémentent
une commande. Chaque classe implémente la
méthode executer(), en appelant des méthodes de
l'objet Recepteur.
Invoqueur : déclenche la commande. Il appelle la
méthode executer() d'un objet Commande.
Recepteur : reçoit la commande et réalise les
opérations associées. Chaque objet Commande
concret possède un lien avec un objet Recepteur.
La partie cliente configure le lien entre les
objets Commande et le Recepteur.
med@[Link]
Design pattern Command
28
Implémentation
/* [Link] */
package cmd;
public class Recepteur {
public void action1(){
[Link]("Action 1 du récepteur");
}
public void action2(){
[Link]("Action 2 du récepteur");
}
}
med@[Link]
Implémentation
/* [Link] */
package cmd;
public interface Commande {
public void executer();
}
/* [Link] */
package cmd;
public class CommandeA implements Commande {
private Recepteur recepteur;
public CommandeA(Recepteur recepteur) {
[Link] = recepteur;
}
@Override
public void executer() {
recepteur.action1();
}
}
med@[Link]
Implémentation
/* [Link] */
package cmd;
public class CommandeB implements Commande {
private Recepteur recepteur;
public CommandeB(Recepteur recepteur) {
[Link] = recepteur;
}
@Override
public void executer() {
recepteur.action2();
}
}
med@[Link]
Implémentation
/* [Link] */
package cmd;
import [Link];
import [Link];
public class Invoqueur {
private Map<String, Commande> commades=new HashMap<String,
Commande>();
public void addCommande(String cmdName,Commande cmd){
[Link](cmdName, cmd);
}
public void invoquer(String cmdName){
Commande cmd=[Link](cmdName);
if (cmd!=null) [Link]();
}
}
med@[Link]
Implémentation
/* [Link] */
package cmd;
public class Application {
public static void main(String[] args) {
Recepteur rec=new Recepteur();
CommandeA commandeA=new CommandeA(rec);
CommandeB commandeB=new CommandeB(rec);
Invoqueur invoqueur=new Invoqueur();
[Link]("CA", commandeA);
[Link]("CB", commandeB);
[Link]("CA");[Link]("CB");
[Link]("CC");
}
}
Action 1 du récepteur
Action 2 du récepteur
med@[Link]
Pattern
Mediator
Exemple (contrôle du trafic aérien)
Solution :
Pattern Mediator
Catégorie :
◦ Comportement
Objectif du pattern
◦ Gérer la transmission d'informations entre des objets
interagissant entre eux.
◦ Avoir un couplage faible entre les objets puisqu'ils n'ont
pas de lien direct entre eux.
◦ Pouvoir varier leur interaction indépendamment.
Résultat :
◦ Le Design Pattern permet d'isoler la
communication entre des objets.
med@[Link]
Pattern Mediator
Raison d’utilisation :
◦ Différents objets ont des interactions. Un
événement sur l'un provoque une action ou des
actions sur un autre ou d'autres objets.
◦ Besoin de centraliser le contrôle et les
communications complexes entre objets
apparentés.
◦ Construire un objet dont la vocation est la
gestion et le contrôle des interactions
complexes entre un ensemble d’objets sans que
les éléments doivent se connaître
mutuellement.
med@[Link]
Responsabilités
Collegue : définit l'interface d'un collègue. Il s'agit
d'une famille d'objets qui s'ignorent entre eux mais
qui doivent se transmettre des informations.
CollegueA et CollegueB : sont des sous-classes
concrètes de l'interface Collegue.
Elles ont une référence sur un objet Mediateur
auquel elles transmettront les informations.
Mediateur : définit l'interface de communication
entre les objets Collegue.
ConcreteMediateur : implémente la
communication et maintient une référence sur les
objets Collegue.
med@[Link]
Design pattern Mediator
40
Implémentation
/* [Link] */
package med;
public class Message {
private String message; private String expediteur;
private String destinataire;
public Message() { }
public Message(String message, String destinataire) {
[Link] = message;
[Link] = destinataire;
}
@Override
public String toString() {
return "Message [message=" + message + ", expediteur=" + expediteur
+ ", destinataire=" + destinataire + "]";
}
// Getters et Setters
}
med@[Link]
Implémentation
/* [Link] */
package med;
import [Link];
import [Link];
public abstract class Mediateur {
protected Map<String, Collegue> collegues=new HashMap<String,
Collegue>();
public abstract void transmettreMessage(Message m);
public void addCollegue(String ref,Collegue a){
[Link](ref, a);
}
}
med@[Link]
Implémentation
/* [Link] */
package med;
public abstract class Collegue {
protected String name;
protected Mediateur mediateur;
public Collegue(String name,Mediateur mediateur) {
[Link]=name;
[Link] = mediateur;
[Link](name, this);
}
public abstract void envoyerMessage(Message m);
public abstract void recevoirMessage(Message m);
med@[Link]
Implémentation
/* [Link] */
package med;
import [Link]; import [Link];
public class MediateurImpl1 extends Mediateur {
private List<Message> conversations=new ArrayList<Message>();
@Override
public void transmettreMessage(Message m) {
[Link]("--------- Début Médiateur ----------");
[Link]("Enregistrement du message");
[Link](m);
[Link]("Transmission du message");
[Link]("From :"+[Link]());
[Link]("To:"+[Link]());
Collegue destinataire=[Link]([Link]());
[Link](m);
[Link]("--------- Fin Médiateur ----------");
}
public void analyserConversation(){
for(Message m:conversations) [Link]([Link]());
}
}
med@[Link]
Implémentation
/* [Link] */
package med;
public class CollegueA extends Collegue {
public CollegueA(String name,Mediateur mediateur) { super(name,mediateur); }
@Override
public void envoyerMessage(Message m) {
[Link]("----------------------");
[Link]("Collègue nom="+name+", Envoi de message");
[Link]([Link]); [Link](m);
[Link]("----------------------");
}
@Override
public void recevoirMessage(Message m) {
[Link]("----------------------");
[Link]("Collègue nom="+name+", Réception du message");
[Link]("From :"+[Link]());
[Link]("Contenu:"+[Link]());
[Link]("Traitement du message par ....."+[Link]);
[Link]("-------------------");
}
}
med@[Link]
Implémentation
/* [Link] */
package med;
public class CollegueB extends Collegue {
public CollegueB(String name,Mediateur mediateur) { super(name,mediateur); }
@Override
public void envoyerMessage(Message m) {
[Link]("----------------------");
[Link]("Collègue nom="+name+", Envoi de message");
[Link]([Link]); [Link](m);
[Link]("----------------------");
}
@Override
public void recevoirMessage(Message m) {
[Link]("----------------------");
[Link]("Collègue nom="+name+", Réception du message");
[Link]("From :"+[Link]());
[Link]("Contenu:"+[Link]());
[Link]("Traitement du message par ....."+[Link]);
[Link]("-------------------");
}
}
med@[Link]
Implémentation
/* [Link] */
import med.*;
public class Application {
public static void main(String[] args) {
MediateurImpl1 mediateur=new MediateurImpl1();
Collegue a1=new CollegueA("C1",mediateur);
Collegue a2=new CollegueA("C2",mediateur);
Collegue b1=new CollegueB("C3",mediateur);
[Link](new Message("je suis à 20 m","C2"));
} }
---------------------- ----------------------
Collègue nom=C1, Envoi de message Collègue nom=C2, Réception du message
--------- Début Médiateur ---------- From :C1
Enregistrement du message Contenu:je suis à 20 m
Transmission du message Traitement du message par .....C2
From :C1 -------------------
To:C2 --------- Fin Médiateur ----------
----------------------
med@[Link]