Vous êtes sur la page 1sur 37

Pattern Design

Master MRSD-2018
K.afdel@uiz.ac.ma

1
Rappel sur l’utilisation du mot Clé CONST

2
Méthodes Constantes :
En ce qui concerne les classes en C++, une méthode constante est une méthode d'une classe qui garantit qu'elle
n'apportera aucune modification à l'état de l'objet sur lequel elle est appelée. Pour déclarer une méthode comme
constante, vous devez ajouter le mot-clé const à la fin de la signature de la méthode.

3
Introduction
L'utilisation Patterns Design présente les avantages suivants:
• Les Patterns Design sont déjà définis et fournissent une approche standard
de l'industrie de développement pour résoudre des problèmes récurrent.
• Gagner du temps avec utilisation judicieuse des Patterns Design.

• L'utilisation de Patterns Design favorise la réutilisabilité, ce qui conduit à


un code plus robuste et hautement maintenable. Cela aide à réduire le
coût total de possession du produit logiciel.

• Comme les Patterns Design sont déjà définis, le code devient facile à
comprendre et à déboguer. Cela conduit à un développement plus rapide
et les nouveaux membres de l'équipe le comprennent facilement.

• Nombreux Patterns Design C++/java existent que nous pouvons utiliser


dans des projets basés sur C++/Java.

4
• Les Patterns Design c++/Java sont divisés en
trois catégories: Patterns Design créatifs,
structurels et comportementaux.
1. Creational Design Patterns
– Singleton Pattern
– Factory Pattern
– Abstract Factory Pattern
– Builder Pattern
– Prototype Pattern

5
2. Structural Design Patterns
– Adapter Pattern
– Composite Pattern
– Proxy Pattern
– Flyweight Pattern
– Facade Pattern
– Bridge Pattern
– Decorator Pattern
3. Behavioral Design Patterns
– Template Method Pattern
– Mediator Pattern
– Chain of Responsibility Pattern
– Observer Pattern
– Strategy Pattern
– Command Pattern
– State Pattern
– Visitor Pattern
– Interpreter Pattern
– Iterator Pattern
– Memento Pattern

6
Creational Design Patterns
Définition
Patterns Design créatifs offrent une solution pour
instancier un objet de la meilleure façon possible
dans des situations spécifiques.

Pattern Singleton
Le modèle Singleton restreint l'instanciation d'une
classe et garantit qu'une seule instance de la
classe existe dans la machine virtuelle java ou
dans l’application. tout instanciation renverra
systématiquement le même unique objet

7
class Singleton_
{ private: // PatternDesignSingleton.cpp : Defines the entry point for
/* Here will be the instance stored. */ the console application.
static Singleton_* instance; //
/* Private constructor to prevent instancing. */
Singleton_(); #include "stdafx.h"
public: #include"Singleton_.h"
/* Static access method. */ #include <iostream>
static Singleton_* getInstance(); //methode doit être déclaré using namespace std;
static et bien sur l'attribut aussi
~Singleton_(void); int _tmain(int argc, _TCHAR* argv[]){
}; //new Singleton(); // Won't work
#include "StdAfx.h" Singleton_ * s = Singleton_::getInstance();
#include "Singleton_.h " // Ok
Singleton_::Singleton_(void) Singleton_ * r = Singleton_::getInstance();
{}
Singleton_* Singleton_::instance = 0; /* The addresses will be the same. */
Singleton_* Singleton_::getInstance()
std::cout << "identication de l'objet s : "<< s
{ if (instance == 0) instance = new Singleton_(); }
return instance;}
<< std::endl;
std::cout << "identication de l'objet r : "<< r
Singleton_::~Singleton_(void) << std::endl;
} system("pause");
{ return 0;
}

8
Atelier 1 Pattern Design
Singleton

9
Pattern Factory
Fabrique : classe dont le rôle est de créer d'autres objets.
• Le design pattern "Factory" est un modèle de conception (pattern) utilisé en
programmation orientée objet pour créer des objets sans spécifier directement leur
classe concrète;

• Patterns Design factory est utilisé lorsque nous avons une super classe avec plusieurs
sous-classes et, en fonction des entrées, nous devons renvoyer l'une des sous-classes;

• Pattern factory délègue la responsabilité d'instanciation d'une classe du programme
client à la classe factory;

10
11
class Voiture { //classe abstract
public: class Voiture {
virtual string getMarque() const = 0; public:
friend ostream &operator<<(ostream &o,const Voiture virtual string getMarque() const = 0;
*v) { friend ostream &operator<<(ostream &o,const Voiture
return o << v->getMarque(); *v) {
} return o << v->getMarque();
}; }
class Renault : public Voiture { // méthode statique pour créer un objet
public: static Voiture *createVoiture
createVoiture(string
(string o);
string getMarque() const { return "Renault"; } };
}; Voiture *Voiture::createVoiture(string origine) {
class Fiat : public Voiture { if (origine=="fr") return new Renault;
public: if (origine=="it") return new Fiat;
string getMarque() const { return "Fiat"; } return 0;
}; }
// cette fois le type concret n’apparaît pas
// cette fonction est indépendante du type concret int main() {
void f(const Voiture *v) { Voiture *v = Voiture::createVoiture("fr");
cout << "Voiture " << v << endl; f(v);
} return 0;
// cette partie du code est dépendante du type concret }
int main() { La méthode createVoiture est une méthode de
Voiture *v = new Renault(); //depend de type objet créé fabrication
f(v); • elle reçoit en paramètre les critères qui permettront
return 0; au concepteur des objets Voiture d’opérer le choix
du type concret
} •dans le code client, les types concrets n’apparaissent
plus.
12 Le code client est devenu entièrement indépendant
des types concrets
Exercice

13
#include <iostream> // méhode Factory simple pour créer des formes
#include <string> class ShapeFactory {
// Classe de base pour toutes les formes géométriques public:
static Shape* createShape(const std::string& shapeType) {
class Shape {
if (shapeType == "cercle") { return new Circle; }
public: else if (shapeType == "carré") { return new Square; }
virtual void draw() = 0; else { return nullptr; // Gestion d'erreur si le type n'est pas reconnu }
}; }
// Sous-classes de formes concrètes };
class Circle : public Shape {
int main() {
public:
// Utilisation de la factory pour créer des formes
void draw() override { Shape* cercle = ShapeFactory::createShape("cercle");
std::cout << "Dessiner un cercle" << std::endl; Shape* carré = ShapeFactory::createShape("carré");
}
}; // Dessin des formes
class Square : public Shape { cercle->draw();
carré->draw();
public:
// Nettoyage de la mémoire
void draw() override { delete cercle;
std::cout << "Dessiner un carré" << std::endl; delete carré;
}
}; return 0;
}

14
ABSTRACT FACTORY
• la fabrique abstraite / l’usine abstraite /
abstract factory permet d’obtenir la
construction d’une famille uniforme d’objets
• permet de séparer les détails
d’implémentation d’une famille d’objet de leur
usage abstrait ou générique

15
#include <iostream> // Implémentation pour macOS
// Interface abstraite pour les boutons
class Button { class MacOSButton : public Button {
public: public:
virtual void render() = 0;};
void render() override {
// Interface abstraite pour les fenêtres std::cout << "Affichage d'un bouton macOS" <<
class Window { std::endl; }};
public:
virtual void create() = 0;};
class MacOSWindow : public Window {
// Fabrique abstraite pour créer des éléments d'interface utilisateur public:
class UIFactory {
public: void create() override {
virtual Button* createButton() = 0; std::cout << "Création d'une fenêtre macOS" <<
virtual Window* createWindow() = 0;}; std::endl; }
// Implémentation pour Windows };
class WindowsButton : public Button {
public:
class MacOSUIFactory : public UIFactory {
void render() override {
std::cout << "Affichage d'un bouton Windows" << std::endl; } public:
}; Button* createButton() override {
class Windows
WindowsWindow : public Window {
public: return new MacOSButton;
void create() override { }
std::cout << "Création d'une fenêtre Windows" << std::endl; }
};
Window* createWindow() override {
class WindowsUIFactory : public UIFactory { return new MacOSWindow;
public:
Button* createButton() override { return new WindowsButton; } }
Window* createWindow() override { return new WindowsWindow; };
}
};
16
int main() {
// Utilisation de l'Abstract Factory pour créer des éléments d'interface
utilisateur Windows
UIFactory* windowsFactory = new WindowsUIFactory;
Button* windowsButton = windowsFactory->createButton();
Window* windowsWindow = windowsFactory->createWindow();
windowsButton->render();
windowsWindow->create();

// Utilisation de l'Abstract Factory pour créer des éléments d'interface


utilisateur macOS
UIFactory* macosFactory = new MacOSUIFactory;
Button* macosButton = macosFactory->createButton();
Window* macosWindow = macosFactory->createWindow();
macosButton->render();
macosWindow->create();

// Nettoyage de la mémoire
delete windowsFactory;
delete windowsButton;
delete windowsWindow;
delete macosFactory;
delete macosButton;
delete macosWindow;

return 0;
}

17
Prototype Pattern

18
PROTOTYPE Pattern
Ce pattern est utilisé lorsque le coût de fabrication d’un objet
est lourd et qu’il est plus facile de dupliquer (cloner) un
objet existant et à modifier la copie ensuite :
• la modification de la copie peut intervenir à deux endroits
différents :
1. dans la méthode de clonage (donc au moment du clonage)
2. dans le code client (donc après le clonage)
• Prototype Interface :Une interface ou une classe abstraite
qui définit une méthode permettant de cloner l'objet. Cette
interface peut également inclure des méthodes pour
personnaliser les attributs de l'objet cloné.
• La méthode de construction est habituellement appelée
clone()

19
#include "StdAfx.h"
#pragma once
class Animal #include "Sheep.h"
{ #include <iostream>
public:
Animal(void);
Sheep::Sheep(void):Animal()
virtual Animal* Clone() =0; { std:: cout << "l'objet Brebis est cree" <<
~Animal(void); std::endl;
};
#include "StdAfx.h" Sheep *sheepObject = 0;}
#include "Animal.h" void Sheep::affiche()
Animal::Animal(void)
{}
{std:: cout <<"Object de type Brebis "<<
Animal::~Animal(void) std::endl;}
{}

#pragma once
#include "StdAfx.h"
Sheep * Sheep::Clone()
#include "Animal.h“
//sheep (Mouton)
{ std:: cout <<"L'objet Brebis vient dêtre
class Sheep : public Animal coloner"<< std::endl;
{ Sheep *sheepObject sheepObject = new Sheep();
public:
Sheep(void); return sheepObject;}
void affiche();
Sheep* Clone() ; Sheep::~Sheep(void)
~Sheep(void);
}; {}
20
#pragma once #include "stdafx.h"
#include "StdAfx.h" #include "CloneFactory.h"
#include "Animal.h" #include "Animal.h"
class CloneFactory #include "Sheep.h"
{ #include <iostream>
public: int _tmain(int argc, _TCHAR* argv[])
CloneFactory(void); { CloneFactory *animalMaker=0 ;
Animal* getClone(Animal *animalSample); // Creates a new Sheep instance
~CloneFactory(void); Sheep *sally = new Sheep();
// Creates a clone of Sally and stores it in its own
}; // memory location
#include "StdAfx.h" Sheep *clonedSheep = (Sheep*) animalMaker->getClone(sally);
#include "CloneFactory.h" // These are exact copies of each other
#include "Animal.h" sally->affiche();
#include "Sheep.h" clonedSheep->affiche();

std::cout <<"Adreese Objet Brebis est :"<< sally << std::endl;


CloneFactory::CloneFactory(void) std::cout << "Adreese Clone du Brebis est :"<<clonedSheep
{} << std::endl;
system("pause");
Animal* CloneFactory::getClone( Animal return 0;
*animalSample) }
{return animalSample->Clone(); //polymorphisme
}

CloneFactory::~CloneFactory(void)
{} 21
Adapter Pattern
• Le modèle d'adaptateur est un modèle de conception structurelle qui permet
à des interfaces incompatibles de fonctionner ensemble. Il sert de pont entre
deux interfaces incompatibles en enveloppant l'interface d'une classe autour
d'une autre interface pour la rendre compatible avec les attentes d'un client.
"converts the interface of a class into another interface that a client wants".

• L’un des exemples les plus concrets du modèle de conception de l’adaptateur


est le chargeur Smartphone.
– La batterie du mobile nécessite 12 volts pour le charger, mais la prise normale produit une
tension de 220V. Le chargeur mobile fonctionne donc comme un adaptateur entre la prise de
charge mobile et la prise murale.
• Les étapes
– Création d’une interface d’adaptateur avec ces méthodes
– Mise en œuvre du modèle d'adaptateur, il existe deux approches:
• Adaptateur de classe : utilise l'héritage java et étend l'interface source, dans notre cas, la
classe Socket.
• Object Adapter : utilise la Composition et adapter contient l'objet source.

22
ADAPTER PATTERN

23
//Class Adapter ToyDuck . Jouet Canard
// Java implementation of Adapter pattern
class BirdAdapter : public ToyDuck
#include <iostream> {
class Bird public:
{public: BirdAdapter(Bird &bird) : bird_(bird) {}
virtual void fly() = 0; void squeak() override
virtual void makeSound() = 0;}; {bird_.makeSound(); }

private:
class Sparrow : public Bird Bird &bird_;};
{public:
void fly() override int main()
{std::cout << "Flying" << std::endl;} { Sparrow sparrow;
void makeSound() override PlasticToyDuck toyDuck;

{std::cout << "Chirp Chirp" << std::endl;}


ToyDuck &birdAdapter = *(new BirdAdapter(sparrow));
};
std::cout << "Sparrow..." << std::endl;
class ToyDuck sparrow.fly();
{public: sparrow.makeSound();
virtual void squeak() = 0;};
std::cout << "ToyDuck..." << std::endl;
toyDuck.squeak();
class PlasticToyDuck : public ToyDuck
{public: std::cout << "BirdAdapter..." << std::endl;
void squeak() override birdAdapter.squeak();
{std::cout << "Squeak" << std::endl;}
}; return 0;}

24
25
Façade Pattern
• Analogie : exemple pour vous aider à comprendre ... un
chauffeur de taxi. Vous dites au chauffeur de taxi "Take me
to PointX" (interface simplifiée unifiée de haut niveau) qui
commence alors une séquence d'actions (tourner la clé,
changer de vitesse, appuyer sur l'accélérateur, etc...) pour
exécuter la tâche. Il fait abstraction de la complexité des
sous-systèmes sous-jacents (boîte de vitesses, moteur, etc.)
pour que vous n'ayez pas à vous en préoccuper. Le
conducteur vous découple également du véhicule
réellement utilisé... vous n'avez pas d'interface directe avec
la voiture. Vous pourriez éventuellement lui donner une
Mercédès mais votre interface avec le conducteur serait
toujours TakeMeTo( X )... vous n'êtes pas lié à un
modèle/marque spécifique de la voiture.

26
Exemple :
• Imaginez une maison intelligente où tout se passe
à distance. Pour allumer les lumières, vous
appuyez sur le bouton "on". Et c'est la même
chose pour la télévision, la climatisation, l'alarme,
la musique, etc.
• Lorsque vous quittez une maison, vous devez
appuyer sur 100 boutons pour vous assurer que
tout est éteint et prêt à partir, ce qui peut être un
peu ennuyeux si vous êtes paresseux.
• Il faut donc définir une Façade "living" &
"Coming". (Les fonctions de la façade
représentent des boutons...). Donc, quand j'arrive
et je repars, je passe un seul appel et tout est
réglé...
27
struct Alarm { struct HouseFacade {
void alarm_on() { cout << "Alarm is on and void go_to_work() {
house is secured"<<endl; } m_ac.ac_off();
void alarm_off() { cout << "Alarm is off and you m_tv.tv_off();
can go into the house"<<endl; } m_alarm.alarm_on();
}; }
struct Ac { void come_home() {
void ac_on() { cout << "Ac is on"<<endl; } m_alarm.alarm_off();
void ac_off() { cout << "AC is off"<<endl; } m_ac.ac_on();
}; m_tv.tv_on();
struct Tv { }
void tv_on() { cout << "Tv is on"<<endl; } private:
void tv_off() { cout << "TV is off"<<endl; } Alarm m_alarm;
}; Ac m_ac;
Tv m_tv;
};
int main() {
HouseFacade hf;
//Rather than calling 100 different on and off
functions thanks to facade I only have 2
functions...
hf.go_to_work();
hf.come_home();
return EXIT_SUCCESS;
}

28
#include <iostream> // Facade pour simplifier l'utilisation du système de gestion de
#include <string> bibliothèque
class LibraryFacade {
#include <vector>
private:
BookManager bookManager;
// Sous-système complexe : Gestion des livres
UserManager userManager;
class BookManager { public:
public: void borrowBook(const std::string& bookTitle, const
void addBook(const std::string& title) { std::string& username) {
std::cout << "Added book: " << title << "\n« ; } bookManager.removeBook(bookTitle);
userManager.addUser(username);
void removeBook(const std::string& title) { std::cout << username << " borrowed " << bookTitle << "\n«
; }
std::cout << "Removed book: " << title << "\n« ; }
void returnBook(const std::string& bookTitle, const std::string&
}; username) {
bookManager.addBook(bookTitle);
// Sous-système complexe : Gestion des utilisateurs userManager.removeUser(username);
class UserManager { std::cout << username << " returned " << bookTitle << "\n« ;}
public: };
void addUser(const std::string& username) {
std::cout << "Added user: " << username << "\n« ; } // Utilisation de la façade
int main() {
LibraryFacade library;
void removeUser(const std::string& username) {
// Utilisation de la façade pour simplifier la gestion des
std::cout << "Removed user: " << username << "\n« ; } emprunts/retours
}; library.borrowBook("The Catcher in the Rye", "John Doe");
library.returnBook("The Catcher in the Rye", "John Doe");
return 0;}

29
Bridge Pattern
• Bridge est un modèle de conception structurelle qui sépare
l'abstraction de l'implémentation de manière à ce que les
deux puissent varier indépendamment.
• Utilisé particulièrement lorsque l'on souhaite éviter un lien
permanent entre une abstraction et son implémentation, ce
qui permet aux deux d'évoluer indépendamment sans
nécessiter de modifications de l'une ou de l'autre.
• Ce Bridge relève du modèle structurel, car il dissocie les
classes d'implémentation et les classes abstraites en
fournissant une structure de pont entre elles.
• The Bridge Design Pattern is all about preferring composition
over inheritance. It helps in lowering coupling.

30
Représentation UML

31
32
33
#include <iostream> // Refined Abstraction: UrgentMessage
#include <string> class UrgentMessage : public Message {
public:
// Implementor interface UrgentMessage(MessagingPlatform* platform) :
class MessagingPlatform { Message(platform) {}
public:
virtual void sendMessage(const std::string& message) const = 0;};
void sendUrgentMessage(const std::string& message) const {
std::cout << "Urgent Message: ";
// Concrete Implementor A: Email
messagingPlatform->sendMessage(message);
class EmailMessaging : public MessagingPlatform {
public: }
void sendMessage(const std::string& message) const override { };
std::cout << "Sending Email: " << message << "\n“; }};
int main() {
// Concrete Implementor B: SMS EmailMessaging email;
class SmsMessaging : public MessagingPlatform { SmsMessaging sms;
public:
void sendMessage(const std::string& message) const override { Message emailMessage(&email);
std::cout << "Sending SMS: " << message << "\n“; }
emailMessage.send("Hello via Email");
};

Message smsMessage(&sms);
// Abstraction
class Message { smsMessage.send("Hello via SMS");
protected:
MessagingPlatform* messagingPlatform; UrgentMessage urgentEmail(&email);
urgentEmail.sendUrgentMessage("Urgent: Meeting at 2 PM via
public: Email");
Message(MessagingPlatform* platform) : messagingPlatform(platform) {}
UrgentMessage urgentSms(&sms);
virtual void send(const std::string& message) const { urgentSms.sendUrgentMessage("Urgent: Meeting at 2 PM via
messagingPlatform->sendMessage(message); } SMS");
};
return 0;
}
Stratégie Pattern

35
Stratégie Pattern
• Le modèle de stratégie est un modèle de conception
comportementale qui permet de sélectionner un
algorithme au moment de l'exécution(également
connu sous le nom de modèle politique).
• L'idée clé est de créer des objets qui représentent
diverses stratégies. Ces objets forment un ensemble de
stratégies parmi lesquelles l'objet de contexte peut
choisir pour varier son comportement en fonction de
sa stratégie.
• Ces objets (stratégies) effectuent la même opération,
ont le même travail et composent la même stratégie
d'interface.

36
Atelier Strategy Pattern

FIN

37

Vous aimerez peut-être aussi