Les différents Design Patterns en C#

Mis à jour 22/05/2025

Cédric BRASSEUR

  • Ancien étudiant de l'Exia.cesi
  • 4 ans consultant chez Amaris, placé chez Euro Information Dev
  • Auto-entrepreneur depuis début 2020 (Création de sites web, applications mobiles & formateur)

Et vous ?

  • Nom, prénom
  • Etudes réalisées 
  • Développeur depuis...
  • Autres infos appréciées

Plan du cours

  • Design Patterns
    • Rappels notions OO
    • Introduction aux Patterns
    • Présentation des différents Patterns
    • Exemples & exercices

  • Pattern MVC

Design Patterns

Objectifs de la semaine

  • Optimiser l’architecture logicielle grace aux designs patterns
     
  • Appréhender les 23 Design Patterns en C#
     
  • Mettre en oeuvre et comprendre l'architecture MVC

Design Patterns

Kesako ?

  • Solutions architecturales à des problèmes objets
  • Réutilisable à des problèmes de dévs récurrents
  • Peu d’algorithmique quand on isole, plus des schémas orientés-objet (UML!!)
  • Façons d’organiser le code pour augmenter
    • Flexibilité du code
    • Maintenabilité du code
    • Extensibilité du code
    • Configurabilité du code
    • (Diminuer) Duplication de code
  • Le plus souvent basé sur des interfaces et abstractions

Les design patterns : classification

  • Patterns créateurs (Singleton, factory, abstract factory)

    • Patterns aidant à la gestion de la création d’objet

  • Patterns structurants (Façade, proxy, decorator, composite, adapter)

    • On parle de travailler sur la partie externe des classes du pattern. L’extensibilité et l’encapsulation des classes.

  • Patterns comportementaux (Strategy, iterator, observer, state)

    • Ici, on travaille sur la partie interne des classes du pattern. La dynamique des classes du pattern. Améliorer la qualité du code, éviter les duplications ou gérer des problématiques connues.

Principes à respecter

Principe n°1

  • Favoriser la composition (liens dynamiques, flexibles) sur l’héritage (lien statique, peu flexible) 
  • Attention il s’agit juste de favoriser car l’héritage est également très utilisé dans les designs patterns

Principe n°2

  • Le code utilisateur d’un pattern doit en priorité TOUJOURS se lier à des abstractions (interfaces, classes abstraites) plutôt qu’à des implémentations concrètes (classes)

Principe n°3

  • Privilégier l’encapsulation faible / découplage fort.                   

Mais d'abord...

Rappel de certaines notions objets importantes

La mise en place de Design Pattern va nécessiter des notions objets simples mais importante pour la compréhension de ces derniers. Nous allons revoir rapidement : 

  • Héritage
  • Interface
  • Composition
  • Agrégation
  • Classe abstraite

L'héritage

L'héritage permet de partager des propriétés et méthodes entre les classes, il suffit d'utiliser le mot clé extends pour que cette classe (fille) hérite de la classe de base (mère).

Le partage de code s'effectue de manière descendante uniquement.

L'héritage (code)

Classe mère

Classe fille

Instanciation

Attention ici !

On peut utiliser les propriétés et méthodes de la mère et de la fille grâce à l'héritage

L'héritage (exemple)

Le but de cet exemple est de mettre en place de l'héritage pour un "Animal". Les classes pouvant en hérité sont "Hibou", "Dragon" et "Tigre".

Animal

Hibou

Dragon

Tigre

L'héritage (exemple)

Classe mère

Classes filles

Instanciation

Chaque animal a sa
propre définition de walk, sauf le tigre qui marche normalement.

Note : new permet de redéfinir la méthode mère

L'héritage (particularités)

Certains mots clés sont à connaître pour l'héritage :

  • new : Permet la redéfinition d'une fonction de la class mère.
  • base : Permet de se référer à un élément de la classe mère (par exemple, le constructeur)
  • virtual : Permet de rendre une
    méthode de la classe mère
    redéfinissable qu'une seule
    fois par une classe fille. 
  • sealed : Permet de redéfinir et
    sceller la méthode virtual
    de la classe mère qu'une
    seule fois (erreur sinon)
  • override : permet de rendre la
    méthode abstraite
    (on y reviendra)

Exercice

Réaliser de l'héritage

 

Cette fois-ci, vous devez réaliser de l'héritage entre une classe mère "Personne" et deux classes filles "Etudiant" et "Formateur".

La personne a un nom et un prénom + constructeur
Le formateur a un sujet à traiter + constructeur & appel du constructeur parent

L'étudiant a une note + constructeur & appel du constructeur parent

Chaque classe fille possèdera donc 3 propriétés public et peuvent les setter à leur convenance.

Réalisez les classes et le Program.cs permettant d'implémenter cet héritage et appelez les propriétés inline pour réaliser des Console.WriteLine() des 3 propriétés pour le Formateur et pour l'Etudiant.

 

PS : Pas besoin que le formateur puisse modifier la note de l'étudiant, il suffit juste que vos différentes classes filles aient leurs propres ajouts de méthodes par rapport aux propriétés demandées.

Diagramme UML de l'exercice précédent

Les interfaces

Les interfaces sont à considérer comme des contrats à respecter, elles contiennent des propriétés et des signatures de méthodes qui seront à implémenter dans la classe héritant de cette interface

Contient une propriété et une méthode qui devra être redéfinie dans les classes implémentant

Contient une propriété et une méthode qui devra être redéfinie dans les classes implémentant

Ici, Cat doit forcément avoir une propriété Name et une méthode MakeSound qui respectent le contrat de l'interface

Association / Agrégation

Une association traduit un lien entre une classe A et une classe B (appel de méthode par exemple).
L'agrégation est une association particulière : l'objet A possède une ou plusieurs instances de B.

Instanciation

Program.cs

La composition

Une composition est une agrégation particulière : toutes les instances de B contenues dans A sont supprimées lorsque A est supprimée.

La composition

Autre exemple plus complexe (pour revoir un peu d'orienté objet supplémentaire)

Instanciation

Exercice

Exercice Orienté Objet

Réaliser une agrégation entre Author et Book.

  • Author doit avoir
    • une propriété public Name et une propriété Email,
    • vous devez créer un constructeur pour remplir ces propriétés.
  • Book doit avoir
    • une propriété public Authors (List<Author>), Price et Name.
    • Un constructeur pour set Name et Price.
  • A vous de trouver comment réaliser une agrégation entre ces deux classes.
  • Pour tester votre code voici ce qui doit fonctionner :

Les classes abstraites

Une classe abstraite (mère) permet de définir les signatures des méthodes et les propriétés qui seront partagés à la classe qui va étendre cette classe abstraite (fille)

Les classes abstraites

L'intérêt principal des classes abstraites est d’informer l’utilisateur (la classe fille) de cette classe qu’une instance de cette dernière n’a pas d’utilité a être instanciée. Exemple : vous devez gérer un centre de location de véhicules (voiture, camion, vélo ….). Vous avez très certainement une classe Vehicule, dont héritera Velo, Voiture, Camion…

Mais le centre de location n'aura jamais besoin d'instancier un Vehicule.

Les classes abstraites peuvent également posséder des méthodes abstraites. Ce sont des méthodes qui ne possèdent pas de corps, et qui devront obligatoirement être surchargée par les classes qui en hérite

Les classes abstraites

Un autre exemple pour mieux comprendre... Nous avons une classe abstraite Shape et deux classes filles Square & Circle. 

Impossible
d'instancier une forme,
Shape est un concept abstrait 

Hérite de Shape
Ce qui lui en donne les propriétés & force à redéfinir "Draw"

Exercice

Exercice Orienté Objet

Réaliser une abstraction entre une classe Fruit et deux classes Orange, Fraise

  • la classe abstraite Fruit doit avoir
    • une propriété public Color,
    • une méthode abstraite Eat
  • Orange doit avoir
    • un constructeur pour remplir la propriété Color provenant de Fruit (l'abstraction dont il hérite)
    • redéfinir la méthode Eat (avec un override) pour préciser qu'on mange une orange dans un Console.WriteLine()
  • Fraise doit avoir 
    • redéfinir la méthode Eat (avec un override) pour préciser qu'on mange une fraise dans un Console.WriteLine()
      • (Cette classe n'a effectivement pas de constructeur paramétré, on ne veut pas lui assigner de couleur. Elle n'a que le constructeur par défaut)

A noter : La classe Fruit ne doit pas pouvoir être instanciée.

Différences entre interfaces, héritage et abstraction

Les trois éléments sont utilisées pour réaliser de la réutilisation de code descendante : 

  • Interface : Contrat à respecter, permet de définir un ensemble de fonctionnalités à redéfinir dans une classe. Ces méthodes ne peuvent pas avoir d'implémentation dans l'interface. (Aucun constructeur possible)
     
  • Héritage : Une classe de démarrage qui propose des fonctionnalités qui sont réutilisables par les classes filles
     
  • Abstraction : Forcer l'implémentation de sous classe, une classe abstraite ne peut pas être instanciée (constructeur protected possible pour initialiser les propriétés de la classe abstraite)

Définition

Définir une dépendance entre un objet observé et un ou plusieurs objets observants.

 

L’objectif étant de pouvoir notifier les objets observants lorsqu’un changement de statut est opéré sur l’objet observé.

Problématique

On a parfois besoin de connaître le changement de statut d’un autre objet. Il est possible d’interroger l’objet en continue pour connaître son statut et le mettre à jour si nécessaire.
Ceci est très gourmand s’il y’a plusieurs abonnés et surtout si on interroge toutes les secondes, alors que le statut change de manière aléatoire ?

Ceci n’est pas efficace. 

Pattern Observer

UML : Pattern Observer

Text

update(ConcreteSuject sub);

Pattern Observer : Avantages

  • Eviter les opérations de PULL massives et simplement effectuer un push / pull lorsque c’est nécessaire.
     

  • Plus concrètement, améliorer la logique métier
     

  • Diminuer le coûts de l’observation
     

  • Supprimer la question de l’intervalle d’interrogation

Exercice

Exercice (Réaliser un pattern Observer)

 

Reprenez le pattern Observer pour observer la modification d'une température et notifier des objets observants ce changement de température.

Chaque modification de température affiche (dans la console) la nouvelle température pour tous les objets observants.
Pensez bien à avoir plusieurs observants.
 

Développez le code du pattern en C#

Exercice (UML à réaliser)

Définition

L'idée principale est de pouvoir mettre en place une certaine stratégie ou ce que l’on va régulièrement appeler un comportement afin de pouvoir en changer dynamiquement au runtime.
Sans pattern stratégie, on serait obligé de multiplier les classes en produit cartésien pour pouvoir avoir autant de combinaisons de comportements que nécessaire. (Horrible)

Problématique

L’héritage est puissant mais il ne permet de partager du code que de manière verticale, c’est-à-dire à ses enfants.


Par contre, si les enfants veulent partager du code entre eux, aucun moyen de le faire à part en dupliquant le code (Horrible).

Pattern Stratégie

UML : Pattern Stratégie

Exemple : Pattern Stratégie

Pattern Stratégie : Avantages

  • Meilleure lisibilité du code. (Pas de duplication, pas de gros pavés de méthodes dans une seule classe)

     

  • S’assurer que chaque élément à sa propre responsabilité (découplage fort)

     

  • Et surtout avoir des comportements interchangeables au runtime sans avoir à multiplier les classes.

Exercice

Exercice (Réaliser un pattern Strategy)

 

Reprenez le pattern Stratégie pour l’appliquer à ce sujet :

Une interface StrategieInterface ayant pour contrat function reagir(PersonneInterface $personne);

 

Quatre classes (Enerve, Geek, Jovial, Sad) chacune implémentant StrategieInterface et redéfinissant donc la méthode réagir:

  • Enervé écrit en majuscule et ajoute des !!! à la fin.
  • Geek remplace les o par des 0
  • Jovial ajoute un :) à la fin
  • Sad ajoute :( à la fin

 

Une interface PersonneInteface ayant pour contrat function donnerPhrase();

 

Une classe Personne qui implémente PersonneInterface et donc redéfini donnerPhrase :

  • return 'Bonjour';

 

Une classe Contexte qui a une stratégie en propriété.

  • Un constructeur pour setter la stratégie
  • une méthode exprimeReaction qui appel la méthode de la stratégie passée dans le constructeur

Développez le code C# correspondant

Exercice (UML exemple à implémenter)

Reaction.React(phrase)

Console.WriteLine(...)

Exercice (Autre exemple à implémenter)

Exercice

Exercice (Réaliser un pattern Strategy)

 

Reprenez le pattern Stratégie pour l’appliquer à ce sujet :

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Développez le code C# correspondant

Définition

Comme son nom l’indique, il a pour objectif de rendre une interface non adaptée à une autre, compatible. En rajoutant un objet intermédiaire nommé « Adapter ».

Problématique

Les interfaces exposées ne sont pas toujours compatibles avec ce que nous avons, il nous faut donc réaliser une adaptation intermédiaire pour pouvoir coupler les deux. 

Pattern Adapter

UML : Pattern Adapter

Comment appliquer l'adapter à ce problème ? 

Pattern Adapter : Avantages

  • Adapter une interface pour qu’elle s’imbrique dans une autre, tout simplement.
     

  • Découplage fort
     

  • Peut-être facilement mis en place même après coup, à moindre coût

Exercice

Exercice (Réaliser un pattern Adapter)

 

Je vous ai envoyé un code avec un nouveau système et un ancien système, votre objectif est de mettre en place l'adapter afin de pouvoir faire fonctionner conjointement l'ancien et le nouveau système pour le client qui utilise ce système.

 

Développez le code du pattern en C#

 

Exercice

Exercice (Réaliser un pattern Adapter)

 

Je vais vous envoyer le code que vous devez adapter pour pouvoir permettre à votre classe cliente (ThirdPartyBillingSystem) d'afficher les employés d'une manière plus propre et ordonnée et correspondre au ClassicCase en List<string>.

Vous devez implémenter une classe
class EmployeeAdapter : HRSystem, ITargetBis.
(Vous pouvez enlever le Bis de ITargetBis, c'est l'interface utilisée) qui appelle GetEmployees afin de retourner une liste d'employé pour adapter l'affichage comme demandé.

 

Développez le code du pattern en C#

Résultat attendu :

Définition

Le pattern singleton est le plus simple des patterns, il permet de s’assurer qu’un objet est instancier qu’une et une seule fois dans toute votre application.


Ce sera toujours la MÊME instance de l’objet quelque soit depuis quel endroit l’objet est appelé. 

Problématique

On instancie un objet quelque part, on y fait des opérations dessus, puis on souhaite à nouveau réutiliser cet objet à un autre endroit.


Pour que les opérations soient gardées en mémoire, on ne peut pas le faire, car on devra réinstancier la classe puis réeffectuer les opérations dessus. (Ou alors rajouter des dépendances inutiles)

Pattern Singleton

UML : Pattern Singleton

Pattern Singleton: Avantages

  • S’assurer qu’un objet est instancier qu’une seule fois et y avoir accès facilement depuis n’importe où dans votre application. 

Pattern Singleton : Désavantages

  • Certains estiment que le pattern singleton est un mauvais pattern (à ne pas confondre avec anti-pattern). Pour deux raisons, à ma connaissance :

    • 1. Le pattern singleton est utilisable uniquement en statique, les débats sont nombreux avec tout ce qui tourne autour du mot clé « static ». Je vous laisserai vous renseigner et vous faire votre propre opinion, mais sachez que pour ma part, je l’utilise très fréquemment.

    • 2. D’après certains développeurs, le fait de dire qu’on est certain que l’on veut une seule instance de son objet à tout jamais dans son application n’est pas en lien avec le fait de faire de son application une application évolutive à toute épreuve.
      Pour eux, afin que ça reste évolutif, on ne peut pas se limiter à une seule instanciation. Habituellement, l'autre possibilité est d'utiliser une Factory.
      Je comprends le point de vue, mais je n’y adhère pas. J’utilise fréquemment le singleton pour instancier ma base de données par exemple. Dans 99,99% des cas, je sais à l’avance que je n’aurai qu’une instance de base de données et ceci n’évoluera pas au fil du temps.

Exercice

Réalisez un pattern Singleton sur un objet President, qui a un nom. Par défaut le nom du président est "Undefined" (ça peut être initialiser dans le constructeur privé). Et qui peut changer de nom. Quelque soit l'endroit où est appelé cet objet President, ce sera toujours le même qui sera appelé. Réalisez une méthode d'affichage du nom du président, exemple : DisplayPresident() qui affiche le nom du président dans un Console.WriteLine.

 

L'objectif était de simuler l'appel de cet objet depuis plusieurs fichiers comme fait dans l'exemple que l'on a fait ensemble.
 

Réalisez le code en C# pour implémenter ce pattern

Définition

Permet d’ajouter dynamiquement des propriétés à un objet.

En pouvant empiler/décorer avec autant d’objets décorable que l’on souhaite.

L’objet décoré et le ou les objets décorants s’utilisent de la même façon, excepté que la plupart du temps, les objets décorants ne peuvent pas exister sans objet à décorer. 

Problématique

Duplication de code et multiplication des classes pour gérer toutes les possibilités (inutiles).

Pattern Decorator

UML : Pattern Decorator

Pattern Decorator : Avantages

  • Simple à mettre en place

  • Evite la multiplication des classes

  • Permet d’ajouter des caractéristiques multiples sans limite (excepté celles définies par l’interface) à un objet de base.

  • Le fait d’envelopper permet de facilement exécuter des opérations qui sont à effectuer sur chaque enveloppe pour en avoir un résultat global (prix d’une boisson par exemple)

  • Attention, ça ne permet pas de connaître l'ordre de décoration !!!

Exercice : Pattern Decorator

  • Adaptez le diagramme vu ensemble en utilisant la problématique suivante :

    • On a une boisson de plusieurs type : café, chocolat au lait, thé, …

    • Chaque boisson peut avoir plusieurs décorations : sucre, caramel, chocolat,…

    • L'objectif est de calculer le prix à la compilation en fonction de la décoration

  • Réalisez le code en C# permettant de mettre ceci en œuvre

  • Décorez un café avec deux fois du caramel et une fois du sucre, par exemple.

Exercice : Pattern Decorator

  • Adaptez le diagramme vu ensemble en utilisant la problématique suivante :

    • On a une pizza de deux trois types possibles : base crème, base tomate, chausson

    • Chaque pizza peut avoir plusieurs décorations : champignons, oeufs, oignon, jambon,... (à vous de mettre ce que vous voulez sur votre pizza)

    • L'objectif est de calculer le prix à la compilation en fonction de la décoration

  • Réalisez le code en C# permettant de mettre ceci en œuvre

  • Décorez une pizza afin de réaliser votre pizza favorite 

Exercice : UML Pizza

Définition

Permet de gérer des états sur des objets tout en gardant la flexibilité d’opérer toutes les actions que voulues sur chaque état.
Sans avoir à enchainer les if (x.state === State.closed) {…}.
On change le state d’un objet et c’est ce state s’auto-gère en fonction des opérations qui sont proposées par l’interface State. 

Problématique

La gestion d’état sur des objets est gérable avec de simples conditions, mais dans le cas où l’on a beaucoup d’état qui peuvent changer en fonction de différentes opérations, le code devient une succession de condition.
D’une part, c’est incompréhensible à premier abord (surtout sans commentaire, ça peut prendre un certain temps) et d’autre part, lorsque l’on veut ajouter un state ou une opération on se retrouve a devoir modifier tout ça au risque de tout péter.

Pattern State

UML : Pattern State

Pattern State : Avantages

  • Modularité du code
     
  • Simplicité pour multiplier les opérations de changement de statut (flexibilité)
     
  • Découplage fort

Exercice

Exercice (Réaliser un pattern State)

 

Réalisez le code permettant d'implémenter un pattern State répondant aux besoins précisés par le diagramme d'états transitions envoyé. 

(Débutant, confirmé, expert, indétrônable, en pouvant sauter des niveaux que ce soit positivement ou non. Excepté quand on arrive à indétrônable)

 

Développez le code du pattern en C# pour implémenter cette problématique d'états.

Exercice

Exercice (Réaliser un pattern State)

 

Si nous avons assez de temps, je vais vous demander de réaliser un pattern State, l’idée ici est de gérer les statut d’une porte :

  • Une interface IGateState + une classe Gate + une classe OpenGateState (IGateState) + une classe ClosedGateState (IGateState)
  • Les méthodes à implémenter sont
    • Enter, pay, payFailed : Ces méthodes doivent modifier le statut suivant l'action réalisée sur le statut courant.

Réalisez le code C# associé à ce pattern

Définition

C’est sensiblement la même chose que le pattern façade, excepté que le pattern proxy exprime un but précis lors du passage par le proxy.
3 types de proxys peuvent être utilisés :

  • Remote : Simple proxy passe plat qui opère comme une simple substitution de l’objet de départ.
  • Virtual : Proxy qui gère l’utilisation de ressources couteuses (en temps, en machine, ou même en argent)
  • Protection : Proxy qui ajoute une couche de sécurité lors de l’appel à votre proxy.

J’insiste sur le fait que c’est plus une vision UML différente qu’une implémentation dans le code différente.

Problématique

Appel d’un composant externe qui nécessite un accès sécurisé, par exemple

Pattern Proxy

UML : Pattern Proxy

Pattern Proxy : Avantages

  • Substitution d’objet, on fait semblant d’être autre chose pour pouvoir réaliser une certaine action
     
  • Opérations coûteuses déléguées (potentiellement pour l'exporter dans un service distant),
     
  • Contrôle d’accès à la ressource,
     
  • Découplage fort

Exercice

Exercice (Réaliser un pattern Proxy)

 

Je vous demande de réaliser un pattern proxy, par exemple en utilisant le proxy pour valider un token d’authentification simple (un simple « toto » == « toto » suffit).

 

Pour ceux qui veulent développer un peu je propose de générer un fichier "Bonjour.txt" contenant 500 000 lignes d'enchaînement de mots générées aléatoirement, ou trouvez une idée d'opération couteuse à effectuer, je suis preneur de bonnes idées.
 

Réalisez le code C# du pattern proposé

Définition

Le pattern façade permet de gérer les multiples dépendances de manière regroupée dans une classe façade qui va nous permettre de définir un certain nombre de dépendances / instanciations à notre place.

 

Il peut également être utilisé comme gestionnaire de méthodes !

Problématique

Dans nos codes, les références à d’autres objets sont multiples et fréquentes. Parfois, il devient difficile ou pénible de devoir instancier les 10 objets dont dépendent l’objet que l’on souhaite. 

Pattern Façade

UML : Pattern Façade

Pattern Façade : Avantages

  • Avantages du pattern :
    • Isoler les dépendances des sous systèmes
    • Packaging depuis une classe, c’est intéressant nan ?
  • Attention par contre:
    • Un des principes peut très facilement être oublié lorsque l’on fait une façade : le principe qui dit qu’on doit connaître que ses voisins les plus proches.
    • Faites attention aux dépendances croisées et faites attention de ne pas multiplier les dépendances dans votre façade.
    • En gros : 
      • A connait B, B connait C, mais A ne DOIT PAS connaître C.

Exercice

Exercice (Réaliser un pattern Façade)

 

Réaliser un pattern façade, l'idée est de mettre en place une façade qui va gérer pour nous l'instanciation de sous classes.

  • Une classe Facade qui va gérer l'ajout d'aliments nécessaires à la réalisation d'un Burger (une simple méthode suffit, ajouterPain, ajouterViande, ajouterTomate, ajouterOignon) en utilisant une classe de gestion du Burger
  • On souhaite concrètement avoir une interface avec toutes les méthode d'ajouts d'aliments et une classe Burger qui implémente ces méthodes (de simple echo suffisent)
  • Et il faut que notre Facade puisse gérer la réalisation de différents burgers, comme un burgerComplet, burgerClassic, burgerNoTomato, burgerNoOinons

 

Réalisez le diagramme UML + le code d'implémentation

 

Mettez de côté vos design pattern dans un dossier en nommant le fichier avec le nom du pattern. Vous m'enverrez un zip avec tous les patterns à la fin de la formation. J'utiliserai ça pour la notation.

Définition

Le pattern command a pour objectif d’encapsuler une requête pour la rendre accessible depuis n’importe quel récepteur et la permettre d’être envoyée depuis n’importe quel émetteur.
L’idée est d’également de s’ajouter la possibilité de « undo » les commandes facilement. (Si en utilisation avec le pattern composite, on peut même effectuer des macro commandes qui exécute plusieurs petites commandes, sans en rendre plus compliqué le undo).

Problématique

Comment proposer un service d’exécution de requêtes à de multiples clients / sujets ?

 

Comment s’assurer que l’on nous demande pas d’exécuter quelque chose que l’on ne sait pas traiter ?

 

De manière générale, comment gérer la commande ? et l'inverser ?

Pattern Command

UML : Pattern Command

Actions

Pattern Command : Avantages

  • Modularité
     
  • Découplage du code et exposition de contrat à respecter pour utiliser le service
     
  • Permet de réaliser les opérations inverses aisément
     
  • Permet également de réaliser une succession d’opérations complexes (si utilisé avec le pattern composite, que l’on verra plus tard)

Exercice

Exercice (Réaliser un pattern Command)

 

Reprenez le pattern Command pour l’appliquer à ce sujet : Gestion du son, pour l’augmenter et le baisser. L’idée va être d’avoir une ICommand qui va pouvoir execute, unexecute une action.
Cette action est définie dans une classe Receiver.
L’Invoker va lui contenir les Command, ainsi que deux méthodes:

  • Monter le son,
  • Baisser le son,
  • (Pour ceux qui veulent coder un peu, faites en sortes de pouvoir gérer un up / down du volume valorisé par un entier. Le unexecute doit pouvoir remettre le son de base à la bonne valeur)

Faites deux Invoker(Remote, Voice)  différents et deux Receiver différents (HiFiSystem, TV)

Réalisez le code C# du pattern proposé

Définition

C’est simple, c’est un pont.
Un pont entre une classe abstraite et une interface permettant d’anticiper le problème de multiplication de classe vu dans le pattern adapter.
L’idée pour différencier les deux, concrètement, c’est que l’adapter corrige un problème de compatibilité alors que le pont l’anticipe pour ne jamais avoir le problème.

Problématique

Deux interfaces ne sont pas forcément compatibles si elles n’ont pas été pensées au départ pour l’être.


La gestion d’un produit cartésien de nos classes nécessite la multiplication des classes, pour un 3x3, le gain est de 3 classes, mais pour du 20x20, le gain est élevé. 

Pattern Bridge

UML : Pattern Bridge

UML : Pattern Bridge explication

Pattern Bridge : Avantages

  • Anticiper les problèmes de compatibilité
     
  • Gestion de produit cartésien entre nos classes (composition multiples de combinaisons) sans avoir à multiplier les classes.
     
  • Modularité et extensibilité du code accrue
     
  • On respecte le contrat de l’interface et de la classe abstraite et on est bon, on fait les combinaisons que l’on souhaite.

Exercice

Exercice (Réaliser un pattern Bridge)

 

Réaliser un pattern bridge, l’idée est de faire un bridge pour pouvoir lier une clé de voiture avec une clé de maison, ou une clé de garage par exemple :

  • Une classe abstraite Door + une interface Key.
  • Des implémentations concrètes de Key (HouseKey, CarKey)
  • Des implémentations concrètes de Door (HouseDoor, CarDoor, GarageDoor)
  • Les méthodes pour ouvrir et fermer
  • Dans un cas, vous devez logger l'ouverture et la fermeture (HouseDoor), d'autres juste l'ouverture (CarDoor) et le dernier juste la fermeture (GarageDoor).

 

(J'ai un autre exercice si celui-ci ne vous parle pas trop)

 

Réalisez le code C# d'implémentation du pattern

 

Définition

Le pattern factory a pour objectif de gérer la construction d’objet différemment qu’avec un « new ».

C’est la factory qui s’assure de la création / suppression de ces objets.

En général, une factory est utilisée lorsque l’on souhaite gérer la façon dont sont créer les objets via des méthodes (Par exemple, RandomCarFactory et RegularCarFactory)

Problématique

On veut parfois ne pas avoir à gérer via le client quel type d’objet sera créer. Ou alors, on souhaite gérer un ordre de création d’objet ou pouvoir le modifier à la volée (par exemple createMutableObject ou createImmutableObject)

Pattern Factory

UML : Pattern Factory

Pattern Factory: Avantages

  • Instanciation dynamique des objets
     
  • Découplage des classes
     
  • Gestion externe de l’instanciation de nos objets, on peut lui faire suivre une logique particulière (toujours dynamiquement)

Exercice

Exercice (Réaliser un pattern Factory simple)

 

Réaliser un pattern Factory afin de pouvoir gérer la création de véhicules différemment à la volée dans le code. Vous allez implémenter :

  • Une interface ICarFactory (qui peut être vide pour l'exo)
  • Une interface ICar (qui peut aussi être vide)
  • Une classe par marque de véhicule Renault, Audi, Mercedes,...
  • Une classe par type d'instanciation de classe : RegularFactory & RandomFactory
  • Dans un cas, la classe génère toujours les mêmes voitures, dans l'autre la classe génère des voitures de manière aléatoire.

A noter : Il n'est pas nécessaire de développer un vrai random pour cet exercice (mais ça rajoute un peu de code alors pourquoi pas !)

Optionnel : Faites une classe qui génère des voitures suivant la suite de Fibonacci. Donc, 1 Renault, 1 Audi, 2 Mercedes, 3 Renault, 5 Audi, 8 Mercedes, 13 Renault,...

Réalisez le diagramme UML + le code d'implémentation

 

Mettez de côté vos design pattern dans un dossier en nommant le fichier avec le nom du pattern. Vous m'enverrez un zip avec tous les patterns à la fin de la formation. J'utiliserai ça pour la notation.

Définition

Le pattern Abstract Factory a le même objectif que le Factory Method. Mais il permet de pouvoir gérer des objets interdépendants en s'assurant d'une compatibilité entre eux.
 

L'objectif est de créer un ensemble d'objets qui ont pour objectif d'être utilisés ensemble.

Problématique

Comment ajouter la possibilité de gérer des objets interdépendants au Factory Method ?

Pattern Abstract Factory

UML : Pattern Abstract Factory

Abstract Factory: Avantages

  • Instanciation dynamique des objets en gérant leur interdépendance
     
  • Découplage des classes
     
  • Gestion externe de l’instanciation de nos objets, on peut leur faire suivre une logique particulière (toujours dynamiquement)
     
  • S'assurer de l'interopérabilité des classes

Factory VS Abstract Factory

Exercice

Exercice (Réaliser un pattern Abstract Factory)

 

Le but de l'exercice est d'implémenter une Abstract Factory pour gérer une interface graphique utilisateur qui peut produire différent styles de boutons et de checkboxes (Windows / MacOS)

  • Produits Abstraits : Définir des interfaces ou des classes abstraites pour les produits : Button et Checkbox.
  • Produits Concrets : Créer des implémentations concrètes pour les boutons et les cases à cocher de style Windows et MacOS.
  • Fabrique Abstraite : Définir une interface de fabrique abstraite qui déclare des méthodes pour créer des produits abstraits (Button et Checkbox).
  • Fabriques Concrètes : Implémenter l'interface de fabrique abstraite pour les styles Windows et MacOS.

 

Réalisez le diagramme UML + le code d'implémentation

 

 

L'UML se trouve sur la page suivante !

Exercice de refactoring guru

Exercice

Exercice (Réaliser un pattern Abstract Factory)

 

Exercice de refactoring guru

Exercice de refactoring guru

Définition

Ce pattern propose une manière de gérer la composition d’objets qui contiennent des objets en arbre.


C’est-à-dire qu’un objet est composé d’un autre objet, qui peut être composé de plusieurs autres objets, etc…


On souhaite pouvoir utiliser les mêmes méthodes que l’on soit dans un nœud composite ou dans un nœud composant.

Problématique

Comment gérer de la récursivité de manière transparente pour le code utilisateur entre objet, sans utiliser de conditionnel sur le type de l’objet ? 

Pattern Composite

UML : Pattern Composite

I

Pattern Composite : Avantages

  • Meilleure lisibilité du code. (Pas de duplication, pas de gros pavés de méthodes dans une seule classe)
     
  • S’assurer que chaque élément à sa propre responsabilité (découplage fort)
     
  • Et surtout avoir des algorithmes interchangeables au runtime sans avoir à multiplier les classes,
     
  • Gérer la récursivité facilement.

Exercice

Exercice (Réaliser un pattern Composite)

 

Réaliser un pattern composite, l'idée est de pouvoir construire une arborescence de <ul> et de <li> imbriqués grâce au pattern composite. Il vous faut :

  • Une interface commune (avec une méthode, par exemple : operation())
  • Une classe pour le <li> (enfant) : Celle-ci contient une propriété en string qu'elle set depuis le constructeur. Ainsi qu'une méthode operation() retournant cette propriété.
  • Une classe pour le <ul> (parent) : Celle-ci contient la propriété listant les classes <li>, ces sous éléments peuvent êtres setté depuis le constructeur & par des méthodes d'ajout et de suppression d'élément. Ici la méthode operation() va parcourir la liste des sous éléments pour réaliser l'affichage des <ul> / <li>

 

Réalisez le diagramme UML + le code d'implémentation

 

Mettez de côté vos design pattern dans un dossier en nommant le fichier avec le nom du pattern. Vous m'enverrez un zip avec tous les patterns à la fin de la formation. J'utiliserai ça pour la notation.

Définition

Ici, l’objectif est de pouvoir parcourir une liste d’objets d’une manière algorithmique implémentée manuellement.
Aujourd’hui ça semble inutile comme pattern, car on a des structures qui utilise ce pattern pour nous. (ArrayList, List, Map, etc…) Tout ce qui est IEnumerable, en gros (IEnumerable c’est notre Iterator) avec les petites surcouches en LinQ qui vont bien…
Mais ça peut arriver que ceci ne soit pas disponible.

Problématique

Gestion d’un ensemble d’objet sans avoir accès à des types qui permettent d’itérer sur la liste.

Pattern Iterator

UML : Pattern Iterator

Pattern Iterator : Avantages

  • Permet de gérer des listes de manière simple et implicite pour la personne qui va utiliser votre code.
     
  • A savoir que vous n’aurez pas forcément toujours la possibilité d’utiliser un type qui gère les itérations pour vous
     
  • On n’est pas obligé de s’arrêter à quelques opérations, on peut en implémenter autant qu’on le souhaite pour parcourir la liste. 

Exercice

Exercice (Réaliser un pattern Iterator)

 

Réaliser un pattern Iterator, ici l'objectif est de mettre en place un iterateur pour lister une collection d'items (WordsCollection implements \IteratorAggregate) en AlphabeticalOrderIterator (implements \Iterator) permettant de lister les items de collection.
A noter que PHP met déjà en place pour vous les interface Iterator & IteratorAggregate.
Vous devez donc :

  • Avoir une collection d'items, un bool reverse et une position pour la classe AlphabeticalOrder et y implémenter les méthodes de IteratorAggregate.
  • La classe WordCollection doit avoir un tableau d'items et proposer les méthodes pour ajouter des items, récupérer la liste des items et une méthode getIterator() ainsi qu'une méthode getReverseIterator().

 

Réalisez le diagramme UML + le code d'implémentation

 

Mettez de côté vos design pattern dans un dossier en nommant le fichier avec le nom du pattern. Vous m'enverrez un zip avec tous les patterns à la fin de la formation. J'utiliserai ça pour la notation.

Exercice difficile

Définition

L'objectif de ce pattern est de mettre en place une abstraction de construction d'objets complexes.
 

Afin qu'un client puisse créer ces objets sans avoir à se soucier de la complexité de création.

 

Problématique

Comment gérer la construction d'objets complexes sans connaitre leur implémentation ? 

 

Comment simplifier l'utilisation de votre code si ces objets complexes ont plusieurs implémentations et représentations ?

Pattern Builder

UML : Pattern Builder

Pattern Builder : Avantages

  • Simplifier l'instanciation d'objets complexes à un client
     
  • Proposer plusieurs implémentations et représentations d'un objets complexes
     
  • Cacher la complexité de création d'objets complexe

Exercice

Implémenter le pattern builder afin de gérer la construction de maisons différentes en étape par étape.

Définition

Le but du pattern est la création de nouveaux objets par duplication d’objets existants appelés prototypes qui disposent de la capacité de clonage.

Problématique

Comment générer un clone d'un objet efficacement ?

Pattern Prototype

UML : Pattern Prototype

Pattern Prototype : Avantages

  • Permettre à un client de demander à une classe qu'il utilise de se dupliquer sans avoir à faire lui même l'opération
     
  • Sauvegarder des états d'objets pour réaliser des opérations dessus et en garder un historique par exemple

Définition

Ce pattern a pour objectif de partager de façon efficace un ensemble de petits objets.

Souvent utilisé pour ajouter des comportements dynamiques à un objet englobant.

(Ex : Une voiture et toutes les options sélectionnées)

Problématique

Comment gérer efficacement des associations entre de nombreux petits objets dynamiques et un objet parent ?

 

Comment s'assurer que l'option ajoutée fait déjà partie de la liste des options déjà crées ?

Pattern Flyweight

UML : Pattern Flyweight

Pattern Flyweight : Avantages

  • Permet de gérer une multitude de petits objets que l'on va associer à un objet parent
     
  • Génération dynamique d'objets et ces objets connaissent uniquement leurs états
     
  • L'objet parent peut contenir une multitude de sous objet et il connaît donc le statut de tous les sous objets

Définition

Le pattern Chain of Responsibility construit une chaîne d’objets telle que si un objet de la chaîne ne peut pas répondre à une requête, il puisse la transmettre à son successeur et ainsi de suite jusqu’à ce que l’un des objets de la chaîne y réponde.

 

Ex : Plusieurs moyens de paiement ou plusieurs instances de serveur pour exécuter une requête

Problématique

Comment avoir plusieurs objets répondant à un critère et permettre l'utilisation en chaîne (si possible pour l'objet) d'objets, afin d'utiliser le premier objet qui peut répondre à ce critère à un moment T ?

Pattern Chain of Responsibility

UML : Pattern Chain Of Responsibility

Pattern CoR : Avantages

  • Permettre la potentielle utilisation de moyens multiples pour répondre à une requête (suivant un ordre particulier), jusqu'à ce qu'un objet de la chaîne puisse répondre.
     
  • Chaîner efficacement des demandes de traitement
     
  • Le client n'a pas besoin de savoir quel maillon de la requête l'effectue

Définition

Son objectif est très souvent associée à la mise en place d'arbres syntaxiques, permettant par exemple de construire un moteur de recherche avec des options de recherche selon les critères retrouvés.

Problématique

Comment gérer un arbre syntaxique généré dynamiquement sous formes d'objets maîtrisés ?

Pattern Interpretor

UML : Pattern Interpretor

Pattern Interpretor : Avantages

  • Gestion d'arbres syntaxiques
     
  • Permet de gérer des arbres syntaxiques simples, pour par exemple effectuer des moteur de recherches internes
     
  • Interpréter une entrée afin de vérifier si des conditions sont présentes en sorties (Ex : Gestion des règles de force de mot de passe)

Définition

Comme son nom l'indique, ce pattern a pour objectif de construire un objet intermédiaire qui gère les possibilités d'interactions entre deux objets, sans que ces deux derniers n'aient à se connaître.

Problématique

Comment gérer l'interaction complexes entre un sous ensemble d'objets qui n'ont pas connaissance les uns des autres ?

Pattern Mediator

UML : Pattern Mediator

Pattern Mediator : Avantages

  • Gérer un système formé d’un ensemble d’objets basés sur une communication complexe conduisant à associer de nombreux objets entre eux
     
  • Améliore la modularité du code
     
  • Dissocier les objets de leurs droits d'inter-communications

Définition

Son but est de sauvegarder et de restaurer l’état d’un objet sans oublier le principe d'encapsulation.

 

On l'utilise en général afin de pouvoir gérer les incompatibilités associés à des changements d'états. Par ex : Gestion des incompatibilités suite au choix des options sur une voiture

Problématique

Comment gérer les changements d'états afin de pouvoir revenir en arrière ? 

 

Comment revenir en arrière sur des incompatibilités entre objets / options ?

Pattern Memento

UML : Pattern Memento

Pattern Memento : Avantages

  • Enregistrer l'état d'un objet afin de pouvoir le restituer plus tard
     
  • Permet d'éviter de recalculer les incompatibilités suite à une annulation de choix
     
  • Respecte le principe d'encapsulation en gardant la possibilité de revenir en arrière sur l'état d'un objet

Définition

Le pattern Template Method permet de reporter dans des sous-classes certaines étapes de l’une des opérations d’un objet, ces étapes étant alors décrites dans les sous-classes.

 

Plus simplement, il permet de factoriser une étape commune dans une classe afin d'éviter la duplication de code.

Problématique

Comment éviter la duplication de code induite lorsqu'une opération complexe comprend plusieurs représentations en plusieurs étapes, dont certaines sont identiques ?   

Pattern Template Method

UML : Pattern Template Method

Pattern Template Method : Avantages

  • Regrouper les étapes / opérations communes à un traitement complexe
     
  • Factoriser des éléments communs au sein des méthodes
     
  • Eviter la duplication de code

Définition

Le pattern Visitor construit une opération à réaliser sur les éléments d’un ensemble d’objets. De nouvelles opérations peuvent ainsi être ajoutées sans modifier les classes de ces objets.

Problématique

Comment ajouter plusieurs opérations à des objets sans avoir à les modifier ?

Pattern Visitor

UML : Pattern Visitor

Pattern Visitor : Avantages

  • Ajouter de multiples opérations à un ensemble d'objet sans avoir à modifier la classe de base
     
  • Modularité de code accrue
     
  • Permettre de laisser le choix des opérations qui peuvent être effectuées sans avoir à se soucier des possibilités d'interdictions

Conclusion

Design Patterns

Attention à la surutilisation des patterns

Petite attention particulière sur la surutilisation : même quand vous aurez l’habitude d’utiliser les design patterns…

Le but des patterns est de répondre à une problématique de code par une conception adaptée ET PAS rendre la conception plus complexe pour mettre des patterns juste parce qu’on veut absolument mettre des patterns partout.

 

C’est assez effrayant le nombre de développeurs en entreprise qui font ça, de mon expérience, je dirai qu’environ 10% des développeurs que j’ai connu avaient ce syndrome. Travailler avec eux était d’autant plus compliqué que leur syndrome était avancé !
Car ils ajoutent une complexité non négligeable à un projet et ensuite pour faire intervenir une ressource non expérimentée et bien… ça fini souvent avec quelqu'un en pleure avant même d’avoir écrit une ligne de code.

Attention à la surutilisation des patterns

Pour appuyer mes propos, imaginez, nous avons vu une architecture MVC (en 3 couches), y ajouter des patterns n’est déjà pas toujours évident, même si les patterns que l’on a vu s’adaptent bien à l’architecture MVC.

D’autres architectures existent, par exemple SOA, qui est une architecture orientée services. Cette architecture contient, en moyenne pour une utilisation normale, entre 10 et 12 couches. Là, on parle d’une complexité déjà impactante en termes d’architecture…

Ajoutez une surutilisation de patterns et seuls les développeurs séniors seront capables de travailler sur ce projet (mais ça ne donnera envie à personne…)

Evitez absolument la complexité dans vos développements, un pattern n'a d'avantage que s'il est employé correctement

Evaluations

Partie pratique

BON COURAGE !

Workshop Design Pattern


Ce workshop va vous faire pratiquer l'ensemble des patterns dans un domaine donné.

L'objectif est de réaliser le maximum de patterns.


L'exercice n'est pas si simple, mais en avançant doucement mais sûrement, vous y arriverez ! 

N'hésitez pas à me poser des questions.


Les patterns les plus simples : 

  • Singleton
  • Stratégie
  • Adapter
  • Decorator
  • State
  • Proxy
  • Facade
  • Observer                                                                                                                                                      

Design Patterns en C#

By Cėdric Brasseur

Design Patterns en C#

  • 734