🏛️ Cours : Les Patrons de Conception (Design Patterns) – L’Intégrale
5.1. Introduction
Les Patrons de Conception sont des solutions éprouvées à des problèmes récurrents. Ils ne sont pas du code, mais des modèles à adapter.
Le saviez-vous ? Ils ont été popularisés par le livre “Design Patterns” (1994) écrit par le “Gang of Four” (GoF) : Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides.
Pourquoi les utiliser ?
-
Vocabulaire commun : Dire “J’utilise un Observer ici” est plus rapide que d’expliquer 10 lignes de logique.
-
Best Practices : Ils respectent naturellement les principes SOLID (surtout OCP et DIP).
-
Maintenabilité : Le code est découpé de manière standardisée.
5.2. Les Patrons de Création (Creational)
Comment créer des objets sans coupler le code à leurs classes concrètes.
5.2.1. 🏭 Factory Method (La Fabrique)
“Déléguer la création aux sous-classes.”
-
Le Problème : Faire
new Chevalier()lie votre code à la classeChevalier. Si vous voulez unArcher, il faut tout changer. -
La Solution : Une interface
UnitFactoryavec une méthodecreateUnit(). -
Lien SOLID : DIP (On dépend de l’interface) & OCP (On ajoute des usines sans toucher au code client).
Extrait de code
@startuml
!theme sunlust
interface Unit {
+ attack()
}
class Chevalier {
+ attack()
}
class Archer {
+ attack()
}
abstract class UnitFactory {
+ createUnit(): Unit {abstract}
}
class ChevalierFactory {
+ createUnit(): Unit
}
class ArcherFactory {
+ createUnit(): Unit
}
Unit <|.. Chevalier
Unit <|.. Archer
UnitFactory <|-- ChevalierFactory
UnitFactory <|-- ArcherFactory
ChevalierFactory ..> Chevalier : creates
ArcherFactory ..> Archer : creates
@enduml
5.2.2. 🏗️ Builder (Le Monteur)
“Construire des objets complexes étape par étape.”
-
Le Problème : Un constructeur avec 10 paramètres (
new Hero(100, 50, "Epée", true, null, ...)). C’est illisible (Télescopic Constructor Anti-pattern). -
La Solution : Un objet
Builderqui configure l’objet final pas à pas.
@startuml
!theme sunlust
class HeroBuilder {
- hero: Hero
+ setHP(int)
+ setWeapon(String)
+ setArmor(String)
+ build(): Hero
}
class Hero
HeroBuilder ..> Hero : creates
note right: Hero h = new HeroBuilder()\n .setHP(100)\n .setWeapon("Sword")\n .build();
@enduml
5.2.3. 👑 Singleton (L’Unique)
“Garantir qu’une classe n’a qu’une seule instance.”
-
Usage :
GameManager,DatabaseConnection,Logger. -
Attention : C’est souvent considéré comme un anti-pattern s’il est mal utilisé (il introduit un état global et cache les dépendances).
public class GameManager {
private static GameManager instance;
private GameManager() {} // Constructeur privé !
public static GameManager getInstance() {
if (instance == null) instance = new GameManager();
return instance;
}
}
📋 Autres Patrons de Création (Résumé)
| Patron | Description Rapide |
|---|---|
| Abstract Factory | Une “Super-Usine” qui crée des familles d’objets liés (ex: ElfFactory crée ElfArcher, ElfMage, ElfCastle). |
| Prototype | Créer un nouvel objet en clonant un objet existant (utile si la création est coûteuse). |
5.3. Les Patrons de Structure (Structural)
Comment assembler des objets et des classes pour former des structures plus grandes.
5.3.1. 🔌 Adapter (L’Adaptateur)
“Faire collaborer des objets incompatibles.”
-
Le Problème : Vous avez un système qui attend
ILogger.log(msg), mais vous voulez utiliser une librairie tierce qui aThirdPartyLog.writeToDisk(msg). -
La Solution : Une classe
Adapterqui enveloppe l’objet incompatible.
5.3.2. 🎁 Decorator (Le Décorateur)
“Ajouter des responsabilités dynamiquement.”
-
Le Problème : Vous avez une classe
Epee. Vous voulez uneEpeeDeFeu, uneEpeeDeGlace, uneEpeeDeFeuEtGlace. L’héritage explose (EpeeDeFeu extends Epee). -
La Solution : Envelopper l’objet.
new Feu(new Glace(new Epee())). -
Lien SOLID : OCP (On ajoute des comportements sans modifier la classe de base).
@startuml
!theme sunlust
interface Arme {
+ getDegats(): int
}
class EpeeBasique {
+ getDegats(): return 10
}
abstract class Decorator implements Arme {
protected arme: Arme
}
class BonusFeu extends Decorator {
+ getDegats(): return arme.getDegats() + 5
}
Arme <|.. EpeeBasique
Decorator o--> Arme
@enduml
5.3.3. 🎭 Facade (La Façade)
“Simplifier une interface complexe.”
-
Le Problème : Pour démarrer le jeu, il faut :
SoundSystem.init(),Gfx.load(),Network.connect(). Le code client devient lourd. -
La Solution : Une classe
GameEngineavec une seule méthodestart().
5.3.4. 🌳 Composite
“Traiter un groupe d’objets comme un seul objet.”
- Usage : Un système de fichiers (Dossier contient Fichiers et Dossiers), ou un Inventaire (Sac contient Objets et Sacs).
📋 Autres Patrons de Structure (Résumé)
| Patron | Description Rapide |
|---|---|
| Bridge | Séparer une abstraction de son implémentation pour qu’elles varient indépendamment (ex: RemoteControl et Device). |
| Proxy | Un substitut pour un autre objet (ex: charger une image lourde seulement quand on l’affiche). |
| Flyweight | Partager l’état commun pour supporter un grand nombre d’objets (ex: afficher 1000 arbres identiques dans un jeu). |
5.4. Les Patrons de Comportement (Behavioral)
Comment les objets communiquent et se répartissent les responsabilités.
5.4.1. 🧠 Strategy (La Stratégie)
“Interchanger des algorithmes à la volée.”
-
Le Problème :
if (mode == "AGRESSIF") { ... } else if (mode == "DEFENSIF") { ... }. -
La Solution :
unit.setComportement(new ComportementAgressif()).
@startuml
!theme sunlust
class Context {
- strategy: Strategy
+ executeStrategy()
}
interface Strategy {
+ execute()
}
class ConcreteStrategyA
class ConcreteStrategyB
Context o-> Strategy
Strategy <|.. ConcreteStrategyA
Strategy <|.. ConcreteStrategyB
@enduml
5.4.2. 📡 Observer (L’Observateur)
“Notifier plusieurs objets d’un changement d’état.”
-
Le Problème : Quand le Héros perd des PV, il faut mettre à jour : la barre de vie, le son (cri), l’écran (rouge). Le Héros ne doit pas connaître ces classes UI.
-
La Solution : Le Héros est un “Sujet”. L’UI est un “Observateur”. Quand PV change, le Héros crie “Notifiez-vous !”.
@startuml
!theme sunlust
class Sujet {
- observers: List
<Observer>
+ attach(o: Observer)
+ notify()
}
interface Observer {
+ update()
}
class BarreDeVieUI {
+ update()
}
class EcranRougeFX {
+ update()
}
Sujet o--> Observer
Observer <|.. BarreDeVieUI
Observer <|.. EcranRougeFX
@enduml
5.4.3. 🚦 State (L’État)
“Modifier le comportement d’un objet quand son état change.”
-
Le Problème : Un monstre se comporte différemment s’il est
CALME,ENERVEouBLESSE. Utiliser desswitch casedevient vite un enfer. -
La Solution : Créer des classes
EtatCalme,EtatEnerve. Le monstre délègue l’action à son état actuel.
📋 Autres Patrons de Comportement (Résumé)
| Patron | Description Rapide |
|---|---|
| Command | Encapsuler une demande sous forme d’objet (ex: Ctrl+Z, file d’attente d’actions). |
| Iterator | Parcourir une collection sans connaître sa structure interne (foreach). |
| Template Method | Définir le squelette d’un algo dans une classe mère, laisser les filles redéfinir certaines étapes. |
| Chain of Responsibility | Passer une demande le long d’une chaîne d’objets (ex: gestionnaire d’événements, support technique). |
| Mediator | Un objet central qui gère les interactions complexes entre objets (tour de contrôle). |
| Memento | Capturer et restaurer l’état interne d’un objet (Système de Sauvegarde). |
| Visitor | Séparer un algorithme de la structure d’objet sur laquelle il opère (Ajouter une opération sans changer les classes). |
| Interpreter | Pour évaluer un langage ou une grammaire. |
5.5. Synthèse : Quel Patron pour mon Projet ?
Pour votre Projet Fil Rouge, voici les plus pertinents :
| Si vous avez besoin de… | Utilisez… |
|---|---|
| Créer des monstres ou objets variés | Factory Method |
| Configurer un personnage complexe | Builder |
| Gérer le moteur de jeu ou la DB | Singleton (avec modération) |
| Avoir des armes avec bonus (Feu, Glace) | Decorator |
| Gérer l’inventaire (Sacs dans Sacs) | Composite |
| Changer l’IA des ennemis (Attaque/Fuite) | Strategy |
| Mettre à jour l’interface (PV, Mana) | Observer |
| Gérer les actions du joueur (Undo/Redo) | Command |