| name | design-patterns-advisor |
| description | Conseille le pattern de conception adapté à un problème donné. Se déclenche avec "design pattern", "quel pattern", "singleton", "factory", "observer", "strategy", "SOLID", "pattern adapté". |
Design Patterns Advisor
Workflow
- Qualifier le problème — poser 1-2 questions précises sur la douleur actuelle : couplage fort ? code dupliqué ? difficile à tester ? trop de
if/switch ? besoin d'extension sans modification ?
- Classifier le besoin — mapper sur la bonne famille :
- Création : instanciation complexe, cache d'instances, familles d'objets
- Structure : adapter une interface, décorer un comportement, encapsuler une hiérarchie
- Comportement : algorithmes interchangeables, notifications, état interne variable
- Architectural : séparation UI/logique, CQRS, pipeline de traitement
- Proposer 2-3 candidats avec critères de décision (voir tableau ci-dessous) — pas de liste exhaustive, uniquement ceux pertinents
- Implémenter le pattern recommandé dans le langage du projet — code complet, copiable, commenté
- Montrer l'avant/après — mettre en évidence les gains mesurables (testabilité, lignes supprimées, points d'extension)
- Signaler les garde-fous — cas où le pattern est inutile ou contre-productif
- Relier aux principes SOLID concernés — expliquer le lien de façon pratique
Critères de décision rapide
| Symptôme du code | Famille | Patterns à considérer |
|---|
new ConcreteClass() éparpillé | Création | Factory Method, Abstract Factory, Builder |
| Une seule instance globale nécessaire | Création | Singleton (avec précaution), Monostate |
| Interfaces incompatibles | Structure | Adapter, Facade |
| Ajout de comportement sans héritage | Structure | Decorator, Proxy |
| Plusieurs algorithmes interchangeables | Comportement | Strategy, Command |
| Couplage fort entre producteur/consommateur | Comportement | Observer, Mediator, Event Bus |
| État interne qui change le comportement | Comportement | State |
| Pipeline de transformations | Comportement | Chain of Responsibility, Pipeline |
| Logique métier + UI mélangées | Architectural | MVC, MVP, MVVM, Clean Architecture |
| Lecture/écriture asymétriques | Architectural | CQRS, Repository |
Exemples concrets par pattern
Strategy — algorithmes interchangeables
Avant (if/switch ingérable) :
public decimal CalculateFee(string type, decimal amount) {
if (type == "standard") return amount * 0.02m;
else if (type == "premium") return amount * 0.01m;
else if (type == "corporate") return amount * 0.005m;
throw new ArgumentException();
}
Après (Strategy) :
public interface IFeeStrategy { decimal Calculate(decimal amount); }
public class StandardFee : IFeeStrategy { public decimal Calculate(decimal amount) => amount * 0.02m; }
public class PremiumFee : IFeeStrategy { public decimal Calculate(decimal amount) => amount * 0.01m; }
public class CorporateFee: IFeeStrategy { public decimal Calculate(decimal amount) => amount * 0.005m; }
public class FeeCalculator(IFeeStrategy strategy) {
public decimal Calculate(decimal amount) => strategy.Calculate(amount);
}
Observer — découplage producteur/consommateur
type Handler<T> = (payload: T) => void;
class EventBus<T> {
private handlers: Handler<T>[] = [];
subscribe(h: Handler<T>) { this.handlers.push(h); }
publish(payload: T) { this.handlers.forEach(h => h(payload)); }
}
const orderBus = new EventBus<{ orderId: string; amount: number }>();
orderBus.subscribe(({ orderId }) => console.log(`Email confirmation ${orderId}`));
orderBus.subscribe(({ amount }) => updateStats(amount));
orderBus.publish({ orderId: "123", amount: 500 });
Decorator — enrichissement sans héritage
from functools import wraps
def retry(max_attempts=3):
def decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return fn(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
return wrapper
return decorator
@retry(max_attempts=3)
def call_external_api(url: str) -> dict:
...
Factory Method — instanciation déléguée
public interface DocumentParser { Document parse(InputStream in); }
public class ParserFactory {
public static DocumentParser create(String contentType) {
return switch (contentType) {
case "application/pdf" -> new PdfParser();
case "text/csv" -> new CsvParser();
case "application/json" -> new JsonParser();
default -> throw new UnsupportedFormatException(contentType);
};
}
}
Repository — abstraction de la persistance
public interface IOrderRepository {
Task<Order?> FindById(Guid id);
Task<IEnumerable<Order>> FindByStatus(OrderStatus status);
Task Save(Order order);
}
public class EfOrderRepository(AppDbContext ctx) : IOrderRepository {
public async Task<Order?> FindById(Guid id) => await ctx.Orders.FindAsync(id);
public async Task Save(Order order) { ctx.Orders.Add(order); await ctx.SaveChangesAsync(); }
}
Garde-fous et anti-patterns
- Singleton : éviter pour tout ce qui a un état mutable ou dépend d'une config runtime — préférer l'injection de dépendances. Le Singleton global tue la testabilité.
- Over-engineering : un
if/else avec 2 branches ne justifie pas un Strategy. Le pattern doit réduire la complexité, pas l'augmenter.
- Abstract Factory trop tôt : ne créer une famille d'objets abstraite que si plusieurs variantes coexistent réellement. Sinon : YAGNI.
- Observer sans cleanup : toujours prévoir le désabonnement (
unsubscribe/Dispose) — sinon fuites mémoire.
- Decorator imbriqué en cascade : au-delà de 3 niveaux, préférer un pipeline explicite ou un middleware pattern.
- Repository sur un CRUD trivial : si toute la logique est
GET/POST/PUT/DELETE sans règle métier, un simple DAO ou l'ORM direct suffit.
- Pattern sans tests : chaque pattern introduit une abstraction — écrire les tests avant de refactorer pour valider le comportement est conservé.
Principes SOLID associés
| Principe | Patterns qui l'expriment directement |
|---|
| S — Single Responsibility | Facade, Command, Repository |
| O — Open/Closed | Strategy, Decorator, Factory Method |
| L — Liskov Substitution | Template Method, Strategy |
| I — Interface Segregation | Adapter, Proxy |
| D — Dependency Inversion | Factory, Abstract Factory, Repository, tous les patterns à base d'interface |
Bonnes pratiques 2026