web-dev-qa-db-fra.com

Comment fonctionne le modèle de stratégie?

Comment ça marche, à quoi ça sert et quand faut-il l'utiliser?

63
Jorge Córdoba

Expliquons le modèle de stratégie de manière simple:

Vous avez une classe Car() avec une méthode run(), vous l'utilisez donc de cette façon dans un pseudo langage:

mycar = new Car()
mycar.run()

Maintenant, vous souhaiterez peut-être modifier le comportement de run() à la volée, pendant l'exécution du programme. Par exemple, vous voudrez peut-être simuler une panne de moteur ou l'utilisation d'un bouton "boost" dans un jeu vidéo.

Il existe plusieurs façons de faire cette simulation: utiliser des instructions conditionnelles et une variable d'indicateur est une façon. Le modèle de stratégie en est un autre: il délègue le comportement de la méthode run() à une autre classe:

Class Car()
{
    this.motor = new Motor(this) 

    // passing "this" is important for the motor so it knows what it is running

    method run()
    {
        this.motor.run()
    }

    method changeMotor(motor)
    {
        this.motor = motor 
    }

}

Si vous voulez changer le comportement de la voiture, vous pouvez simplement changer le moteur. (Plus facile dans un programme que dans la vraie vie, non? ;-))

C'est très utile si vous avez beaucoup d'états complexes: vous pouvez les modifier et les maintenir beaucoup plus facilement.

78
e-satis

Problème

Le modèle de stratégie est utilisé pour résoudre des problèmes qui pourraient (ou sont prévus) pourraient être mis en œuvre ou résolus par différentes stratégies et qui possèdent une interface clairement définie pour de tels cas. Chaque stratégie est parfaitement valide en elle-même, certaines des stratégies étant préférables dans certaines situations qui permettent à l'application de basculer entre elles pendant l'exécution.

Exemple de code

namespace StrategyPatterns
{
  // Interface definition for a Sort algorithm
  public interface ISort
  {
    void Sort(List<string> list)
  }

  // QuickSort implementation
  public class CQuickSorter : ISort
  {
    void Sort(List<string> list)
    {
      // Here will be the actual implementation
    }
  }

  // BubbleSort implementation
  public class CBubbleSort : ISort
  {
    void Sort(List<string> list)
    {
      // The actual implementation of the sort
    }
  }

  // MergeSort implementation
  public class CMergeSort : ISort
  {
    void Sort(List<string> list)
    {
      // Again the real implementation comes here
    }
  }

  public class Context
  {
    private ISort sorter;

    public Context(ISort sorter)
    {
      // We pass to the context the strategy to use
      this.sorter = sorter;
    }

    public ISort Sorter
    {
      get{return sorter;)
    }
  }

  public class MainClass
  {
    static void Main()
    {
       List<string> myList = new List<string>();

       myList.Add("Hello world");
       myList.Add("Another item");
       myList.Add("Item item");

       Context cn = new Context(new CQuickSorter());
       // Sort using the QuickSort strategy
       cn.Sorter.Sort(myList);
       myList.Add("This one goes for the mergesort");
       cn = new Context(new CMergeSort());
       // Sort using the merge sort strategy
       cn.Sorter.Sort(myList);
    }
  }
}
38
Jorge Córdoba
  • Qu'est-ce qu'une stratégie? Une stratégie est un plan d'action conçu pour atteindre un objectif spécifique;
  • "Définissez une famille d'algorithmes, encapsulez chacun d'eux et rendez-les interchangeables. La stratégie permet à l'algorithme de varier indépendamment des clients qui l'utilisent. " (Gang of Four);
  • Spécifie un ensemble de classes, chacune représentant un comportement potentiel. Le basculement entre ces classes modifie le comportement de l'application. (la stratégie);
  • Ce comportement peut être sélectionné au moment de l'exécution (en utilisant le polymorphisme) ou au moment du design;
  • Capturez l'abstraction dans une interface, enterrez les détails d'implémentation dans les classes dérivées;

enter image description here

  • Une alternative à la stratégie consiste à modifier le comportement de l'application à l'aide d'une logique conditionnelle. (MAUVAIS);
  • L'utilisation de ce modèle facilite l'ajout ou la suppression de comportements spécifiques, sans avoir à recoder et retester tout ou partie de l'application;

  • Bonnes utilisations:

    • Lorsque nous avons un ensemble d'algorithmes similaires et son besoin de basculer entre eux dans différentes parties de l'application. Avec Strategy Pattern, il est possible d'éviter les ifs et de faciliter la maintenance;
    • Lorsque nous voulons ajouter de nouvelles méthodes à la superclasse qui n'ont pas nécessairement de sens pour chaque sous-classe. Au lieu d'utiliser une interface de manière traditionnelle, en ajoutant la nouvelle méthode, nous utilisons une variable d'instance qui est une sous-classe de la nouvelle interface de fonctionnalité. C'est ce qu'on appelle la composition: au lieu d'hériter d'une capacité par héritage, la classe est composée d'objets ayant la bonne capacité;
21
Malf

Directement à partir de article Wikipedia sur le modèle de stratégie :

Le modèle de stratégie est utile dans les situations où il est nécessaire d'échanger dynamiquement les algorithmes utilisés dans une application. Le modèle de stratégie vise à fournir un moyen de définir une famille d'algorithmes, d'encapsuler chacun comme un objet et de les rendre interchangeables. Le modèle de stratégie permet aux algorithmes de varier indépendamment des clients qui les utilisent.

6
Bill the Lizard

Un modèle étroitement lié est le modèle Délégué; dans les deux cas, une partie du travail est transférée à un autre composant. Si je comprends bien, la différence entre ces modèles est la suivante (et corrigez-moi si je me trompe):

  • Dans le modèle Delegate, le délégué est instancié par la classe englobante (délégante); cela permet la réutilisation du code par composition plutôt que par héritage. La classe englobante peut être consciente du type concret du délégué, par ex. s'il invoque son constructeur lui-même (par opposition à l'utilisation d'une usine).

  • Dans le modèle Strategy, le composant qui exécute la stratégie est une dépendance fournie au composant englobant (utilisant) via son constructeur ou un setter (selon votre religion). Le composant utilisateur ignore totalement quelle stratégie est utilisée; la stratégie est toujours invoquée via une interface.

Quelqu'un connaît-il d'autres différences?

6
Andrew Swan

Pour ajouter aux réponses déjà magnifiques: Le modèle de stratégie a une forte similitude avec le passage d'une fonction (ou des fonctions) à une autre fonction. Dans la stratégie, cela se fait en enveloppant ladite fonction dans un objet suivi de passer l'objet. Certaines langues peuvent transmettre directement des fonctions, elles n'ont donc pas du tout besoin du modèle. Mais d'autres langages ne peuvent pas transmettre de fonctions, mais pouvez passer des objets; le motif s'applique alors.

Surtout dans les langages de type Java, vous constaterez que le type Zoo du langage est assez petit et que votre seul moyen de l'étendre est de créer des objets. Par conséquent, la plupart des solutions aux problèmes consistent à trouver un modèle; une façon de composer des objets pour atteindre un objectif précis. Les langues avec des zoos de type plus riches ont souvent des façons plus simples de résoudre les problèmes - mais les types plus riches signifient également que vous devez passer plus de temps à apprendre le système de type. Les langues avec une discipline de frappe dynamique obtiennent souvent un moyen sournois de contourner le problème également.

5