Imaginez une application de facturation qui doit calculer les taxes selon la province du client. La solution naïve ? Un long enchaînement de blocs if/else qui grossit chaque fois qu’une nouvelle province s’ajoute, devient difficile à tester et impossible à maintenir sans toucher au cœur de la logique. C’est exactement le genre de problème que le patron de conception Stratégie résout élégamment : il permet d’isoler chaque algorithme de calcul dans sa propre classe, de les rendre interchangeables, et de les injecter à la volée — sans jamais modifier le code qui les utilise.
Le Patron Stratégie (Strategy Pattern)
Ce patron isole des algorithmes interchangeables derrière une interface commune. Au lieu d’utiliser de longs blocs if/else imbriqués pour gérer différents modes de calcul, on injecte la stratégie voulue à la volée.
// sans utiliser le patron de conception La stratégieif(quebecTax) { // calculer avec la TVQ et TPS séparés} else if (ontarioTax) { // calculer avec la HST} // ajouter un autre else if pour chaque province et territoires
Le contexte qui utilise la stratégie (couplage lâche)
L’interface commune (le contrat)
Dans certains cas, sans utiliser le patron de conception, le code peut facilement des centaines de lignes surtout si le code pour chaque condition est laissé dans le bloc if/else.
//L'interface commune (Le contrat)public interface StrategieCalcul { public double calculer(double montant);}
Cette interface permet d’avoir plusieurs implémentations pour calculer. Par exemple. quand le calcul est différent pour chaque province ou territoire.
Les implémentations concrètes (les algorithmes isolés)
Chaque classe implémente l’interface est permet ainsi d’enlever le bloc if/else pour le remplacer par un ensemble d’implémentations concrètes comme ceci:
//Les implémentations concrètes (Les algorithmes isolés)public class CalculTaxeQuebec implements StrategieCalcul { public double calculer(double montant) { return montant * 0.14975; }}public class CalculTaxeOntario implements StrategieCalcul { public double calculer(double montant) { return montant * 0.13; }}
Finalement, la classe qui a besoin du calcul, a un attribut de type interface StrategieCalcul définie à la première étape. Une méthode de type setter est ajouté pour plus de flexibilité.
Le contexte qui utilise la stratégie (Couplage lâche)public class Facture { private StrategieCalcul strategie; public Facture(StrategieCalcul strategie) { this.strategie = strategie; } public void setStrategie(StrategieCalcul strategie) { this.strategie = strategie; // Permet de changer d'algorithme à la volée } public double genererTotal(double montant Base) { return montantBase + strategie.calculer(montantBase); }}-
Quand utiliser le patron Stratégie ?
- Algorithmes interchangeables : plusieurs variantes d’un même traitement coexistent (calcul de taxes, de rabais, de frais de livraison selon la région ou le type de client).
- Règles métier qui varient selon le contexte : le comportement doit pouvoir changer à l’exécution sans recompiler ni modifier la classe principale.
- Éviter les longues chaînes
if/elseouswitch: chaque condition devient une classe autonome, testable indépendamment. - Respect du principe Ouvert/Fermé (Open/Closed) : ajouter une nouvelle stratégie (ex. : une nouvelle province) ne nécessite aucune modification du code existant.
- Faciliter les tests unitaires : chaque stratégie est une petite unité isolée, simple à tester sans dépendances externes.
Quand l’éviter ?
- Seulement deux variantes stables : si le comportement ne changera jamais et qu’il n’y a que deux cas, un simple
if/elseest plus lisible et moins complexe à maintenir. - Logique triviale : créer une hiérarchie de classes pour encapsuler une seule ligne de calcul est souvent de la sur-ingénierie (over-engineering).
- Équipe peu familière avec les patrons : si le code doit être lu et maintenu par des développeuses débutantes, la multiplication des classes peut nuire à la lisibilité sans apporter de bénéfice réel.
- Performance critique : l’indirection supplémentaire (appel via interface) peut être un problème dans des boucles très intensives, bien que ce cas soit rare dans les applications de gestion courantes.
Comparaison avec d’autres patrons
| Critère | Stratégie (Strategy) | État (State) | Commande (Command) |
|---|---|---|---|
| Intention principale | Choisir un algorithme parmi plusieurs | Modifier le comportement selon un état interne | Encapsuler une action pour l’exécuter plus tard |
| La stratégie est changée par… | Le client (code appelant) | L’objet lui-même selon son état | L’invocateur (invoker) |
| Structure | Interface + classes concrètes interchangeables | Interface + classes représentant chaque état | Interface + classes encapsulant chaque action + historique possible |
| Exemple typique | Calcul de taxes selon la province | Comportement d’un personnage selon sa santé (sain / blessé) | Bouton Annuler (Undo) dans un éditeur de texte |
| Point commun | Tous trois utilisent le polymorphisme via une interface commune pour déléguer un comportement | Tous trois utilisent le polymorphisme via une interface commune pour déléguer un comportement | Tous trois utilisent le polymorphisme via une interface commune pour déléguer un comportement |
Pour aller plus loin
Le patron Stratégie n’est qu’un exemple parmi les nombreux patrons de conception abordés de façon pédagogique dans le livre D’étudiante à professionnelle TI. Conçu spécialement pour les étudiantes en technologie de l’information, cet ouvrage illustre les concepts architecturaux avec des exemples concrets tirés du milieu professionnel québécois — exactement comme dans cet article. Pour en savoir plus ou vous procurer votre exemplaire, rendez-vous sur la page Livres du site.

Laisser un commentaire