Strategi (designmønster)

Denne artikkelen kan inneholde upubliserte arbeider eller ubekreftede uttalelser (oktober 2014).

Du kan hjelpe ved å legge til referanser eller fjerne upublisert innhold.

I Software Engineering , den boss strategien er en utforming mønster (design mønster) av atferdsmessige algoritmer gjennom hvilke kan velges fortløpende i løpet av hvor lang tid det under visse betingelser.

Strategimønsteret er nyttig i situasjoner der det er nødvendig å bytte algoritmene som brukes i en applikasjon dynamisk. Strategimønsteret er ment å gi midler til å definere en familie av algoritmer, kapsle hver av dem som et objekt og gjøre dem utskiftbare. Denne sjefen lar algoritmer endres uavhengig av klienter som bruker dem.

bruk

Siden et objekt kan utføre flere forskjellige behandlinger, avhengig av en variabel eller en tilstand.

Struktur

Eksempel i C ++

#include <iostream> #include <memory> // IStrategie est l’interface permettant d’exécuter un algorithme class IStrategie { public: void execute() { process(); } // NVI virtual ~IStrategie() = default; // Héritage, donc destructeur public virtuel private: virtual void process() = 0; // IStrategie::process() 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 { private: // Chaque Algorithme redéfinit la façon de procéder void process() override { std::cout << "Traitement A" << std::endl; } }; class AlgorithmeB : public IStrategie { private: void process() override { std::cout << "Traitement B" << std::endl; } }; class AlgorithmeC : public IStrategie { private: void process() override { std::cout << "Traitement C" << std::endl; } }; // Contexte est la classe visible par le client. // Elle fait le lien entre les demandes du client et l’algorithme (ou les algorithmes) à utiliser. class Contexte final { private: std::unique_ptr<IStrategie> strategie; public: Contexte(std::unique_ptr<IStrategie> new_strategie) : strategie(std::move(new_strategie)) {} void execute() { strategie->execute(); } void setAlgorithme(std::unique_ptr<IStrategie> new_strategie) { strategie = std::move(new_strategie); } }; int main() { Contexte contexte(std::make_unique<AlgorithmeA>()); contexte.execute(); // Le contexte va effectuer le traitement A contexte.setAlgorithme(std::make_unique<AlgorithmeB>()); contexte.execute(); // Le contexte va effectuer le traitement B contexte.setAlgorithme(std::make_unique<AlgorithmeC>()); contexte.execute(); // Le contexte va effectuer le traitement C return 0; }

Se abstrakt klasse og ren virtuell funksjon .

Eksempel i C #

Lignende ideer fører til realisering ved hjelp av grensesnitt.

Objektet som må ha en tilpassbar strategi ved kjøretid implementerer IStrategie: det samme grensesnittet som andre objekter. Hovedobjektet delegerer utførelsen av oppgaven til et annet medlemsobjekt som implementerer IStrategie.

Medlemsobjektet blir erklært i klassen som et grensesnitt, dets implementering spiller ingen rolle, vi kan derfor endre strategien ved kjøretid. Denne måten å gjøre ting på ligner på prinsippet om injeksjon av avhengighet .

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 meure 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, 4)); // 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 cueillir " + "des champignons dans le Périgord."); } // une exécution aux petits oignons kevin.PrendreLaVille(); } }

Eksempel i Delphi

kilde: 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.

Smalltalk eksempel

Her kan en bils oppførsel endres avhengig av kjørestrategien:

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

Vi kan derfor skrive:

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

Java-eksempel

Vi vet at flying () og kvakking () er delene av Duck-klassen som varierer fra and til and.

For å skille denne oppførselen fra Duck-klassen, trekker vi ut disse to metodene fra klassen og lager et nytt sett med klasser for å representere hver atferd.


Duck bruker attributter av BehaviorVol og BehaviorCancan- grensesnittstypen ("støyen" fra anda).

Det er disse grensesnittene som kapsler inn koden for metodene performVol () og performCancan () .

Det er disse metodene vi ønsker å kapsle inn, i henhold til strategidesignmønsteret, for å gjøre dem utskiftbare.

Til tross for vårt ønske om å gjøre disse metodene utskiftbare:

  • det er fremdeles andre metoder som vi ønsker å holde vanlige: her svømmer () metoden .
  • og andre metoder som vi ønsker spesifikke for den valgte implementeringen: her display () -metoden .
public abstract class Canard { ComportementVol comportementVol; ComportementCancan comportementCancan; public Canard() { } public abstract void afficher(); public void effectuerVol() { comportementVol.voler(); } public void effectuerCancan() { comportementCancan.cancaner(); } public void nager() { System.out.println("Tous les canards flottent, même les leurres!"); } public void setComportementVol(ComportementVol comportementVol) { this.comportementVol = comportementVol; } public void setComportementCancan(ComportementCancan comportementCancan) { this.comportementCancan = comportementCancan; } }

Nå skal vi spesialisere denne Duck- klassen ved å implementere to nye klasser som arver fra Duck . Colvert- klassen :

public class Colvert extends Canard { public Colvert() { comportementVol = new VolerAvecDesAiles(); comportementCancan = new Cancan(); } public void afficher() { System.out.println("Je suis un vrai colvert"); } }

Og PrototypeCanard- klassen  :

public class PrototypeCanard extends Canard { public PrototypeCanard() { comportementVol = new NePasVoler(); comportementCancan = new Cancan(); } public void afficher() { System.out.println("Je suis un prototype de canard"); } }

The Behavior Flight attributt er et objekt som har klassen implementerer Behavior Flight grensesnitt .

public interface ComportementVol { public void voler(); }

Den ' attributtet QuackBehavior er et objekt som har klassen implementerer grensesnitt QuackBehavior.

public interface ComportementCancan { public void cancaner() ; }

Det er mulig å spesifisere så mange FlyBehavior og QuackBehavior enn nødvendig, ganske enkelt ved å opprette en ny klasse som implementerer begge grensesnittene. Det er da opp til disse klassene å implementere fly () ...

public class VolerAvecDesAiles implements ComportementVol { public void voler() { System.out.println("Je vole !!"); } } public class NePasVoler implements ComportementVol { public void voler() { System.out.println("Je ne sais pas voler"); } }

... og kvakksalver () for å spesifisere ønsket oppførsel.

public class Cancan implements ComportementCancan { public void cancaner() { System.out.println("Cancan"); } }


Merknader og referanser

  1. Freeman, Eric, 1965- , Freeman, Elisabeth. , Sierra, Kathy. og Bates, Bert. ( oversatt  fra engelsk), designmønstre, head first , Beijing / Cambridge / Paris etc., O'Reilly,2005, 637  s. ( ISBN  2-84177-350-7 og 978-2-84177-350-3 , OCLC  181354957 , les online )