Strategie (návrhový vzor)

Tento článek může obsahovat nepublikovanou práci nebo neověřená prohlášení (října 2014).

Můžete pomoci přidáním odkazů nebo odebráním nepublikovaného obsahu.

V softwarovém inženýrství je šéf strategie je návrhový vzor (konstrukční vzor) algoritmů chování, jehož prostřednictvím mohou být vybrány za běhu v době provádění za určitých podmínek.

Vzor návrhu strategie je užitečný v situacích, kdy je nutné dynamicky vyměnit algoritmy použité v aplikaci. Strategický vzor má poskytnout prostředky k definování rodiny algoritmů, zapouzdřit každý z nich jako objekt a učinit je zaměnitelnými. Tento šéf umožňuje měnit algoritmy bez ohledu na klienty, kteří je zaměstnávají.

použití

Protože objekt může provádět několik různých ošetření, v závislosti na proměnné nebo stavu.

Struktura

Příklad v 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; }

Viz abstraktní třída a čistě virtuální funkce .

Příklad v C #

Podobné nápady vedou k realizaci pomocí rozhraní.

Objekt, který musí mít za běhu adaptabilní strategii, implementuje IStrategie: stejné rozhraní jako ostatní objekty. Hlavní objekt deleguje provedení úkolu na jiný členský objekt, který implementuje IStrategie.

Členský objekt deklarovaný ve třídě jako rozhraní, na jeho implementaci nezáleží, můžeme proto změnit strategii za běhu. Tento způsob dělá věci podobný principu vstřikování závislosti .

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(); } }

Příklad v Delphi

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

Příklad Smalltalk

Zde lze změnit chování automobilu v závislosti na strategii jízdy:

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

Můžeme tedy napsat:

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

Příklad Java

Víme, že létání () a kvákání () jsou části třídy Duck, které se liší od kachny po kachnu.

Chcete-li oddělit tato chování od třídy Duck, extrahujeme tyto dvě metody ze třídy a vytvoříme novou sadu tříd, která bude představovat každé chování.


Canard používá atributy typu rozhraní BehaviorVol a BehaviorCancan („hluk“ kachny).

Právě tato rozhraní zapouzdřují kód pro metody performVol () a performCancan () .

Právě tyto metody chceme zapouzdřit podle vzoru návrhu strategie, aby byly zaměnitelné.

Navzdory naší touze učinit tyto metody zaměnitelnými:

  • stále existují další metody, které chceme ponechat běžné: zde metoda swim () .
  • a další metody, které chceme mít specifické pro zvolenou implementaci: zde metoda display ().
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; } }

Nyní se specializujeme na tuto třídu Duck implementací dvou nových tříd zděděných od Ducka . Třída Colvert:

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

A třída PrototypeCanard  :

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"); } }

Chování Flight atribut je objekt, jehož třída implementuje chování Flight rozhraním .

public interface ComportementVol { public void voler(); }

" Atribut QuackBehavior je objekt, jehož třída implementuje rozhraní QuackBehavior.

public interface ComportementCancan { public void cancaner() ; }

Je možné zadat tolik FlyBehavior a QuackBehavior, než je nutné, jednoduše vytvořením nové třídy, která implementuje obě rozhraní. Je tedy na těchto třídách, aby implementovaly funkci 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"); } }

... a quack () k určení požadovaného chování.

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


Poznámky a odkazy

  1. Freeman, Eric, 1965- , Freeman, Elisabeth. , Sierra, Kathy. a Bates, Bert. ( přeloženo  z angličtiny), Designové vzory, nejprve hlava , Peking / Cambridge / Paříž atd., O'Reilly,2005, 637  s. ( ISBN  2-84177-350-7 a 978-2-84177-350-3 , OCLC  181354957 , číst on-line )