Menu
Coddy logo textTech

Patron Stratégie

Fait partie de la section Programmation Orientée Objet du Journey Dart de Coddy — leçon 93 sur 110.

Le patron de conception Stratégie (Strategy pattern) vous permet de définir une famille d'algorithmes, d'encapsuler chacun d'eux dans sa propre classe et de les rendre interchangeables au moment de l'exécution. Au lieu de coder le comportement en dur dans une classe, vous injectez le comportement via une interface, ce qui vous permet de changer de stratégie sans modifier la classe qui les utilise.

Considérez un système de paiement dans lequel vous souhaitez prendre en charge différents modes de paiement. Plutôt que d'utiliser des conditions pour gérer chaque méthode, vous définissez une interface de stratégie et créez des implémentations concrètes :

abstract class PaymentStrategy {
  void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with Credit Card');
}

class PayPalPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with PayPal');
}

class ShoppingCart {
  PaymentStrategy _paymentStrategy;

  ShoppingCart(this._paymentStrategy);

  void setPaymentStrategy(PaymentStrategy strategy) {
    _paymentStrategy = strategy;
  }

  void checkout(double total) {
    _paymentStrategy.pay(total);
  }
}

void main() {
  var cart = ShoppingCart(CreditCardPayment());
  cart.checkout(99.99);  // Paid $99.99 with Credit Card

  cart.setPaymentStrategy(PayPalPayment());
  cart.checkout(49.99);  // Paid $49.99 with PayPal
}

Le ShoppingCart ne sait pas et ne se soucie pas de la manière dont le paiement fonctionne - il délègue simplement à la stratégie actuellement définie. Vous pouvez ajouter de nouveaux modes de paiement en créant de nouvelles classes de stratégie sans toucher au code du panier. Ce patron est idéal lorsque vous avez plusieurs façons d'effectuer une action et que vous souhaitez les sélectionner ou basculer entre elles de manière dynamique.

challenge icon

Défi

Facile

Construisons un système de formatage de texte en utilisant le pattern Strategy ! Vous allez créer un système où différentes stratégies de formatage peuvent être appliquées au texte, permettant aux utilisateurs de basculer entre les formats de manière dynamique sans modifier le processeur de texte principal.

Vous organiserez votre code en deux fichiers :

  • formatting_strategies.dart : Créez votre système de stratégie ici. Définissez une classe abstraite FormattingStrategy avec une méthode String format(String text). Ensuite, implémentez trois stratégies concrètes :
    • UppercaseStrategy - convertit le texte en majuscules
    • LowercaseStrategy - convertit le texte en minuscules
    • TitleCaseStrategy - met en majuscule la première lettre de chaque mot (séparés par des espaces, première lettre de chaque mot en majuscule, le reste en minuscules)
    Créez également une classe TextProcessor qui contient une FormattingStrategy. Elle doit avoir un constructeur qui accepte une stratégie initiale, une méthode setStrategy() pour changer la stratégie au moment de l'exécution, et une méthode process(String text) qui applique la stratégie actuelle et renvoie le résultat formaté.
  • main.dart : Importez vos stratégies de formatage et démontrez comment le pattern Strategy permet un changement de comportement dynamique. Créez un TextProcessor en commençant par la UppercaseStrategy. Traitez le texte 'hello world' et affichez le résultat. Ensuite, passez à la LowercaseStrategy, traitez 'HELLO WORLD', et affichez le résultat. Enfin, passez à la TitleCaseStrategy, traitez 'the quick brown fox', et affichez le résultat.

Cela démontre la puissance du pattern Strategy : votre TextProcessor n'a pas besoin de connaître les détails du fonctionnement du formatage. Il délègue simplement à la stratégie actuellement définie, ce qui facilite l'ajout de nouvelles options de formatage sans modifier le processeur !

Sortie attendue :

HELLO WORLD
hello world
The Quick Brown Fox

Aide-mémoire

Le pattern Strategy définit une famille d'algorithmes, encapsule chacun d'eux dans sa propre classe et les rend interchangeables au moment de l'exécution. Au lieu de coder le comportement en dur, vous l'injectez via une interface.

Définissez une interface de stratégie :

abstract class PaymentStrategy {
  void pay(double amount);
}

Créez des implémentations concrètes de la stratégie :

class CreditCardPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with Credit Card');
}

class PayPalPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with PayPal');
}

Créez une classe de contexte qui utilise la stratégie :

class ShoppingCart {
  PaymentStrategy _paymentStrategy;

  ShoppingCart(this._paymentStrategy);

  void setPaymentStrategy(PaymentStrategy strategy) {
    _paymentStrategy = strategy;
  }

  void checkout(double total) {
    _paymentStrategy.pay(total);
  }
}

Utilisez le pattern en injectant et en changeant de stratégie :

var cart = ShoppingCart(CreditCardPayment());
cart.checkout(99.99);  // Paid $99.99 with Credit Card

cart.setPaymentStrategy(PayPalPayment());
cart.checkout(49.99);  // Paid $49.99 with PayPal

La classe de contexte délègue le comportement à la stratégie sans connaître les détails d'implémentation. Ajoutez de nouvelles stratégies en créant de nouvelles classes sans modifier le code existant.

Essayez vous-même

import 'formatting_strategies.dart';

void main() {
  // TODO: Créer un TextProcessor en commençant par UppercaseStrategy
  
  // TODO: Traiter le texte 'hello world' et afficher le résultat
  
  // TODO: Passer à LowercaseStrategy
  
  // TODO: Traiter 'HELLO WORLD' et afficher le résultat
  
  // TODO: Passer à TitleCaseStrategy
  
  // TODO: Traiter 'the quick brown fox' et afficher le résultat
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet