05 DesignPatterns
05 DesignPatterns
http://sourcemaking.com/design_patterns
https://refactoring.guru/design‐patterns/
Introduction Introduction
3 4
Introduction Introduction
Les patrons de conception respectent le plus souvent les 5 principes SOLID KISS (Keep It Simple, Stupid)
S: Single Responsability Principle C’est un principe général en ingénierie qui n’est pas propre à l’informatique
Une classe doit avoir une et une seule responsabilité Un programme simple est toujours plus
O: Open/Closed simple à maintenir
Une classe doit être ouverte à l’extension mais fermée à la modification Il est aussi plus simple à vérifier pour les
L: Liskov Substitution test et la validation des fonctionnalités
Une instance de type T doit pouvoir être remplacée par une instance de type G tant que Il faut éviter l’inflation de fonctionnalités
G est un sous type de T
I: Interface Segregation Principle
Préférer des interfaces spécifiques plutôt qu’une seule interface générique
« La simplicité est la sophistication suprême. »
D: Dependency Inversion Principle Léonard de Vinci
Il faut dépendre des abstractions et pas des implémentations
5 6
Introduction Introduction
DRY (Don’t Repeat Yourself) YAGNI (You Aren’t Gonna Need It)
Le copier coller de code est mal ! Toute fonctionnalité doit être documentée, testée et débuggée
Si vous êtes amené à dupliquer du code, c’est que vous avez besoin de Si une fonctionnalité n’est pas demandée elle n’est probablement
refactoriser ou de reprendre la conception pas nécessaire
Si elle n’est pas spécifiée, les tests et la documentation ne pourront
Il faut utiliser les patrons de conception
pas être définis complètement
L’héritage et la composition peuvent l’éviter
Ajouter des fonctionnalités inutiles complexifie le logiciel
On parle de dette technique
En ajoutant une première fonctionnalité inutile on est souvent tenté
d’en ajouter d’autres ‐> Effet boule de neige
7 8
Le patron Singleton
Les patrons de création C’est le patron de conception le plus simple et le plus connu mais il en existe
cependant plusieurs versions
Le « Lazy »
Le « synchronized »
Le « eager »
Le « Holder »
10
Cette solutionne fonctionne parfaitement tant qu’il n’y a pas d’accès Ce patron répond au problème précédent avec une pénalité importante sur les
concurrents performances
Si deux threads accèdent simultanément à la méthode getInstance() on peut Passage par une file d’attente de processus qui n’est pas nécessaire si les accès concurrents
construire deux fois l’objet sont réduits
11 12
Le patron Singleton Le patron Singleton
13 14
Définition du GoF: "Define an interface for creating an object, but let La version à une seule fabrique
subclasses decide which class to instantiate. The Factory method lets a class
defer instantiation it uses to subclasses.“
Pour résumer, une fabrique consiste à isoler la création des objets de leur
utilisation
En effet le type va souvent dépendre du contexte d’utilisation
Le client ne va pouvoir déterminer le type qu’à l’exécution
Elle vise également à centraliser la création des objets en fonction du contexte
15 16
Le patron Factory (Fabrique) Le patron Abstract Factory
Pizza
Prenons un exemple simple: La pizza Le patron Abstract Factory permet de répondre à ce problème
Il peut y avoir plusieurs types de pizzas: On procède par héritage d’une classe abstraite pour les extensions plutôt qu’en
ReginaPizza modifiant le contenu des méthodes
MargheritaPizza public abstract class PizzaFactory{
ReginaPizza MargheritaPizza
public abstract Pizza getPizza();
…
}
On définit ensuite une Fabrique concrète par type de Pizza à retourner
Si nous reprenons la version avec une Fabrique, une solution est public class ReginaFactory extends PizzaFactory{ public class MargheritaFactory extends PizzaFactory{
public class PizzaFactory{ public Pizza getPizza(){ public Pizza getPizza(){
public Pizza getPizza(String nom){ return new ReginaPizza(); return new MargheritaPizza();
if (nom==REGINA) return new ReginaPizza(); } }
else return new MargheritaPizza(); } }
}
} Pour ajouter un nouveau type, il suffit d’écrire une nouvelle classe héritant de la
Fabrique abstraite
Pbm: Si on veut ajouter un nouveau type de pizza à la carte, il faut modifier la
méthode getPizza() ce qui viole la règle O de SOLID
17 18
La version à plusieurs fabriques Pour le langage Java une version alternative de ce Pattern existe qui repose
sur l’utilisation d’une interface pour définir l’Abstract Factory
Permet de gérer les problèmes d’héritages multiples
public interface PizzaFactory{
public Pizza getPizza();
}
19 20
Le patron Abstract Factory
21
Motivation
La persistance des données est très souvent nécessaire dans une application mais
elle peut prendre plusieurs formes
Fichiers
Bases de données locales ou réparties
Services web
…
Diagramme de séquence associé
Cette persistance peut évoluer au fil du temps
Il faut donc éviter de la disperser dans le code pour en faciliter la maintenabilité
23 24
Le patron Adaptateur Le patron Adaptateur
Définition du GoF : “Convert the interface of a class into another interface Le code à écrire est donc limité à l’adaptateur pour faire un lien entre les
that clients expect. The adapter pattern lets classes work together that classes à relier
couldn’t otherwise because of incompatible interfaces.”
L’idée est de proposer des classes qui servent d’adaptateur à des classes
existantes pour leur permettre de fonctionner avec d’autres classes
25 26
Cette interface peut être implémenter par plusieurs classes comme par
exemple
27 28
Le patron Adaptateur Le patron Adaptateur
29 30
Ce patron est très pratique pour permettre de relier deux parties de code ne Le patron décorateur est assez proche du précédent
présentant pas de types communs Il ajoute des fonctionnalités à l’interface existante contrairement à l’adaptateur
Faites tout de même attention en l’utilisant car permettre une adaptation entre qui lui essayait d’adapter l’interface
deux objets très dissemblables risque de vous poser des problèmes pour fournir
les fonctionnalités attendues…
Source:
http://www.dofactory.com/net/design‐
patterns
31 32
Le patron Décorateur Le patron Décorateur
Pizza
Si nous reprenons l’exemple de la pizza comme pouvons nous ajouter des baseDePizza
ingrédients à volonté ? + getIngredients(): String
En créant de nouveaux types qui héritent de Pizza
ReginaPizzaAuxAnchoix
ReginaPizza MargheritaPizza PizzaDecorateur
ReginaPizzaAuxCapres
ReginaPizzaAuxOignons + getIngredients(): String + getIngredients(): String
…
Cette solution n’est pas satisfaisante car rapidement on voit se profiler une
explosion du nombre de classes et de types
PizzaAuxCapres PizzaAuxOlives
‐ Pizza maPizza ‐ Pizza maPizza
L’objectif de ce patron est d’éviter cette explosion de classes en empaquetant
+ getIngredients(): String + getIngredients(): String
un objet à l’intérieur d’un autre pour lui ajouter des fonctionnalités
33 34
Ce qui donne en Java public abstract class Pizza { Le patron Façade permet de mettre en place simplement une interface pour
public abstract String getIngredients()
} accéder à une librairie, un framework ou un ensemble complexe
Il permet de masquer cette complexité en exposant un sous ensemble de
public class ReginaPizza extends Pizza{ fonctionnalités
public String getIngredients(){ return "Jambon, Fromage, Champignons"; }
} Il offre souvent moins de fonctionnalités que le système masqué
Permet cependant de faire évoluer le système sans que la façade soit affectée
public abstract class PizzaDecorateur extends Pizza {
protected Pizza baseDePizza; Avantage lorsqu’on n’a besoin que de quelques fonctionnalités dans une grosse librairie
}
Source: Wikipédia
35 36
Le patron Façade
37
Il permet de faire partager un comportement par plusieurs classes Ce patron permet de s’assurer que d’étendre une partie du code sans toucher
La méthode TemplateMethod définit un comportement général qui s’appuie sur à l’algorithme général
deux méthodes abstraites: PrimitiveOperation1() et Permet d’éclater un code monolithique en plusieurs étapes qui peuvent ensuite
PrimitiveOperation2() être surchargées dans des sous‐classes sans changer le comportement global
Les deux méthodes sont ensuite surchargées dans les classes héritantes
Source: refactoring.guru
39 40
Le patron Observable (Observer) Le patron Observable (Observer)
L’objectif de ce patron est de permettre de signaler à un observateur les L’objet observé est appelé le plus souvent sujet
changements qui surviennent sur un objet On peut également le qualifier de publieur dans la mesure où il va publier des
En Java, nous l’avons déjà manipulé à travers le PropertyChangeSupport informations aux observateurs
Il revient à définir un mécanisme de souscription pour informer les observateurs Cet objet propose une méthode permettant à un observateur de s’enregistrer
des changements qui surviennent sur l’objet observé pour obtenir des notifications sur les changements d’états
Les observateurs de leur coté doivent implémenter une même interface dans
laquelle la méthode de notification est définie
Cela permet d’homogénéiser la manière dont le sujet va répondre
Source: refactoring.guru
41 42
Source: refactoring.guru
43 44
Le patron Observable (Observer) Le patron Observable (Observer)
45 46
47 48
Le patron d’états (State pattern) Le patron d’états (State pattern)
Le but est de permettre à un objet de changer son comportement lorsque son Prenons un exemple simple: Un distributeur automatique
état interne change
Il propose plusieurs
Le changement semble produire un changement de classe vu de l’extérieur de comportements lorsque l’on
l’objet insère de la monnaie et que
l’on sélectionne un produit
Diagramme UML Il distribue le produit
L’objet Context est Il distribue le produit puis
composé d’un état rend la monnaie
Il ne distribue pas le
L’état est réalisé par
produit car le montant
deux classes différentes
fourni est trop faible
En général des Il ne distribue pas le
singletons produit car il n’a plus de
produits demandés
Source: sourcemaking
Source: Head First Design Patterns
49 50
51 52
Le patron médiateur Le patron médiateur
Le rôle du patron médiateur est d’encapsuler la manière dont des objets vont Exemple de situation problématique
interagir
Il évite les communications directes entre objets
Assure un couplage faible entre les objets à mettre en relation car ils n’ont pas
Source:
besoin de se référencer pour interagir refactoring.guru
Il met en général en place un mécanisme d’évènement pour permettre aux objets de
dialoguer
Source:
refactoring.guru
Source: refactoring.guru
53 54
Ce patron est utile lorsque les classes sont fortement liées les unes aux autres Diagramme de classe par rapport à l’exemple
Il permet de spécifier ces relations au sein de la classe de médiateur
De manière plus générique le patron se représente de la manière suivante Ce patron présente de forte similarité avec le patron observateur
Les composants possèdent Ils sont souvent interchangeables
une référence vers
l’interface médiateur
Ils peuvent cependant être utilisés en même temps
Permet de les réutiliser
Le but du médiateur est d’assurer un couplage faible entre les composants
dans d’autre contexte avec
d’autres médiateurs Le but de l’observateur est de fournir une méthode pour notifier des
Les composants n’ont pas changements
connaissance les uns des Une implémentation du médiateur intègre en fait observateur dans le sens où
autres l’objet médiateur joue le rôle du sujet
Le médiateur déclare une
méthode de communication La principale différence repose sur le fait que le médiateur peut avoir des
avec les composants références permanentes vers les composants
Source:
refactoring.guru
L’observateur repose sur une notion d’abonnement/désabonnement
57 58
Exemple
59 60
Le patron médiateur Le patron Visiteur
Ce patron est utile lorsque l’on a des opérations à effectuer sur des objets
complexes
Permet de limite le code de ces objets à la logique métier et d’externaliser le reste
61 62
L’interface Visiteur déclare les Visiteur permet de n’affecter qu’une partie des composants au sein d’une
méthodes de visite pour les hiérarchie de composants
composants On met le code concerné dans une classe visiteur et seuls les composants ayant
Les Visiteurs implémentent besoin de ce comportements vont accepter ce visiteur
cette interface pour les objets
concrets Il respecte les principes Open/Close et Single Responsability de SOLID
L’interface Element déclare une Un nouveau comportement est ajouté sous la forme d’un nouveau Visiteur
méthode pour accepter les
visiteurs Le visiteur peut également servir à récupérer de l’information lorsqu’il visite
Les composants concret des systèmes complexes
implémentent la méthode pour
accepter les visiteurs Par contre, il est nécessaire de mettre à jour les visiteurs à chaque fois qu’un
Dans la méthode accept ils Source:
refactoring.guru
composant est ajouté ou supprimé de la hiérarchie et il en peut pas accéder
font appel à visit(…) au champs/méthodes privées
63 64
Le patron Visiteur Le patron Visiteur
Exemple (source:sourcemaking)
65 66
Source: Sourcemaking
67 68
Le patron Stratégie Le patron Stratégie
69 70