Stratégie (patron de conception)

Un article de Wikipédia, l'encyclopédie libre.
Aller à : navigation, rechercher

En génie logiciel, le patron stratégie est un patron de conception (design pattern) de type comportemental grâce auquel des algorithmes peuvent être sélectionnés à la volée au cours du temps d'exécution selon certaines conditions.

Le patron de conception stratégie est utile pour des situations où il est nécessaire de permuter dynamiquement les algorithmes utilisés dans une application. Le patron stratégie est prévu pour fournir le moyen de définir une famille d'algorithmes, encapsuler chacun d'eux en tant qu'objet, et les rendre interchangeables. Ce patron laisse les algorithmes changer indépendamment des clients qui les emploient.

Utilisation[modifier | modifier le code]

Dès lors qu'un objet peut effectuer plusieurs traitements différents, dépendant d'une variable ou d'un état.

Structure[modifier | modifier le code]

Patron Stratégie en UML
Patron Stratégie en LePUS3 (legend)

Exemple en C++[modifier | modifier le code]

#include <iostream>
using namespace std;
 
class IStrategie
{
public:
        virtual void execute() = 0; // execute() est une fonction virtuelle pure
			            // et de ce fait IStrategie est une classe abstraite
			            // autrement dit une classe qui ne peut être instanciée
};
 
class AlgorithmeA : public IStrategie
{
public:
        void execute()
        {
                cout << "Traitement A" << endl;
        }
};
 
class AlgorithmeB : public IStrategie
{
public:
        void execute()
        {
                cout << "Traitement B" << endl;
        }
};
 
class AlgorithmeC : public IStrategie
{
public:
        void execute()
        {
                cout << "Traitement C" << endl;
        }
};
 
class Element
{
private:
        IStrategie* strategie;
 
public:
        Element(IStrategie* strategie) : strategie(strategie)
        {
        }
 
        void execute()
        {
                strategie->execute();
        }
};
 
void main()
{
        AlgorithmeA algoA;
        AlgorithmeB algoB;
        AlgorithmeC algoC;
 
        Element elementA(&algoA);
        Element elementB(&algoB);
        Element elementC(&algoC);
 
        elementA.execute();     // L'élément A va effectuer le traitement A
        elementB.execute();     // L'élément B va effectuer le traitement B
        elementC.execute();     // L'élément C va effectuer le traitement C
 }

Voir classe abstraite et fonction virtuelle pure.

Exemple en C#[modifier | modifier le code]

Des idées semblables amènent à une réalisation à l'aide d'interface.

L'objet qui doit avoir une stratégie adaptable à l'exécution implémente IStrategie : la même interface que d'autres objets. L'objet principal délègue l'exécution de la tâche à un autre objet membre qui implémente IStrategie.

L'objet membre étant déclaré dans la classe comme une interface, son implémentation importe peu, on peut donc changer de stratégie à l'exécution. Cette manière de faire se rapproche du Principe de l'injection de dépendance.

using System;
 
/// <summary> La manière dont le grand général guidera ses troupes</summary>
interface IStrategie {
    void MettreEnOeuvre();
}
 
/// <summary> Ce grand homme qui fera bientôt des choix décisifs </summary>
class SeigneurDeLaGuerre {
 
    /// <summary> une stratégie générique </summary>
    IStrategie _strategie;
 
    /// <summary> comment changer de stratégie </summary>
    public IStrategie Strategie { set { _strategie = value; } }
 
    /// <summary> délégation de la tâche </summary>
    public void PrendreLaVille() {
        _strategie.MettreEnOeuvre();
    }
}
 
class DéfoncerLePontLevisDeFace : IStrategie {
    public void MettreEnOeuvre() {
        Console.WriteLine("Prendre la ville de face en défonçant le pont levis.");
    }
}
class PasserParLaFaceNord : IStrategie {
    public void MettreEnOeuvre() {
        Console.WriteLine("Prendre la ville en escaladant la muraille nord.");
    }
}
class AttendreQueLaVilleSeRende : IStrategie {
    public void MettreEnOeuvre() {
        Console.WriteLine("Attendre qu'il n'y ait plus rien à manger en ville "
            + "et que tout le monde meurre de faim.");
    }
}
class SeMarierAvecLaCousineDuDuc : IStrategie {
    public void MettreEnOeuvre() {
        Console.WriteLine("Organiser un mariage avec la cousine du Duc "
            + "alors qu'elle rejoint la ville de retour des Baléares "
            + "et inviter toute la ville à une grande fête.");
    }
}
/// <summary> Différentes situations </summary>
enum Météo {
    IlFaitBeau,
    IlYADuBrouillard,
    IlFaitTropChaudPourTravailler,
    IlPleut
}
 
class Program {
    static void Main() {
 
        // notre acteur
        var kevin = new SeigneurDeLaGuerre();
 
        // les aléas du système
        var météo = (Météo)(new Random().Next(0, 3));
 
        // une liaison tardive
        switch (météo) {
            case Météo.IlFaitBeau: 
                kevin.Strategie = new DéfoncerLePontLevisDeFace(); break;
            case Météo.IlYADuBrouillard: 
                kevin.Strategie = new PasserParLaFaceNord(); break;
            case Météo.IlFaitTropChaudPourTravailler:
                kevin.Strategie = new AttendreQueLaVilleSeRende(); break;
            case Météo.IlPleut:
                kevin.Strategie = new SeMarierAvecLaCousineDuDuc(); break;
            default: 
                throw new Exception("Nan finalement seigneur de la guerre c'est "
                    + "pas cool comme job : vous décidez d'aller élever "
                    + "des chêvres dans le Perigord.");
        }
 
        // une exécution aux petits oignons
        kevin.PrendreLaVille();
    }
}

exemple en Delphi[modifier | modifier le code]

source : Delphi GOF Design Patterns (CodePlex)

unit strategy;
 
interface
 
type
 
 TContext = class;
 
 IStrategy = interface
 ['{7F63C143-98D0-4B8C-A02B-894D145BB745}']
   function Move(c: TContext): integer;
 end;
 
 TStrategy1 = class(TInterfacedObject, IStrategy)
 public
   function Move(c: TContext): integer;
 end;
 
 TStrategy2 = class(TInterfacedObject, IStrategy)
 public
   function Move(c: TContext): integer;
 end;
 
 TContext = class
 private
   FStrategy: IStrategy;
   FCounter: integer;
 public
   constructor Create(counter: integer);
   function Algorithm: integer;
   procedure SetStrategy(s: IStrategy);
   property counter: integer read FCounter write FCounter;
 end;
 
implementation
 
{ TStrategy1 }
 
function TStrategy1.Move(c: TContext): integer;
begin
 c.Counter := c.Counter + 1;
 Result := c.Counter;
end;
 
{ TStrategy2 }
 
function TStrategy2.Move(c: TContext): integer;
begin
 c.Counter := c.Counter - 1;
 Result := c.Counter;
end;
 
{ TContext }
 
function TContext.Algorithm: integer;
begin
 Result := FStrategy.Move(Self)
end;
 
constructor TContext.Create(counter: integer);
begin
 inherited;
 FCounter := counter;
 FStrategy := TStrategy1.Create;
end;
 
procedure TContext.SetStrategy(s: IStrategy);
begin
 FStrategy := s;
end;
 
end.
 
 
{ fichier projet }
program Behavioral.strategy.Pattern;
{$APPTYPE CONSOLE}
 
uses
  SysUtils,
  strategy in 'strategy.pas';
 
var
 context: TContext;
 i: integer;
 
begin
 try
   context := TContext.Create(12);
   context.SetStrategy(TStrategy1.Create);
   try
     for i := 0 to 30 do begin
       if i =  15 then begin
         WriteLn(#10 + '|| ');
         context.SetStrategy(TStrategy2.Create);
       end;
       Write(IntToStr(context.Algorithm) + ' ');
     end;
     ReadLn;
   finally
     context.Free;
   end;
 except
   on E:Exception do
     Writeln(E.Classname, ': ', E.Message);
 end;
end.

Exemple en Smalltalk[modifier | modifier le code]

Ici, on peut modifier le comportement d'une voiture en fonction de la stratégie de conduite:

ConduiteSport>>avance
  Transcript show: 'à fond à fond'; cr
 
ConduiteTranquille>>avance
  Transcript show: 'on roule doucement'; cr
 
Voiture>>modeSport
  strategieConduite := ConduiteSport new
 
Voiture>>modeTranquille
  strategieConduite := ConduiteTranquille new
 
Voiture>>avance
  strategieConduite avance

On peut donc écrire:

maVoiture := Voiture new.
 
maVoiture modeSport.
maVoiture avance. "Affiche 'à fond à fond'"
 
maVoiture modeTranquille.
maVoiture avance. "Affiche 'on roule doucement'"