Strategi (designmönster)

Den aktuella versionen av sidan har ännu inte granskats av erfarna bidragsgivare och kan skilja sig väsentligt från versionen som granskades den 6 juli 2017; kontroller kräver 11 redigeringar .
Strategi
Strategi
Sorts beteendemässiga
Ändamål låter dig använda olika affärsregler eller algoritmer beroende på sammanhanget.
Gäller i ärenden när man befinner sig på samma plats, beroende på systemets (eller dess miljö) aktuella tillstånd, måste olika algoritmer användas
fördelar
  • inkapsling av implementeringen av olika algoritmer, systemet blir oberoende av möjliga förändringar i affärsregler;
  • anropa alla algoritmer på ett standardsätt;
  • att inte använda switchar och/eller villkorliga uttalanden.
Minus skapa ytterligare klasser
Relaterade mallar Brygga , mallmetod , adapter
Beskrivs i Design Patterns Ja

Strategi ( eng.  Strategy ) är ett beteendedesignmönster utformat för att definiera en familj av algoritmer , kapsla in var och en av dem och säkerställa deras utbytbarhet. Detta låter dig välja en algoritm genom att definiera lämplig klass. Strategimallen låter dig ändra den valda algoritmen oavsett vilka klientobjekt som använder den.

Nyckelfunktioner

Utmana

Välj den typ av klient som ska användas (eller den typ av data som behandlas). Om en regel används som inte kan ändras behöver man inte hänvisa till strategimönstret.

Motiv

Lösning

Separation av algoritmvalsprocedur från dess implementering. Detta gör att urval kan göras baserat på sammanhang.

Medlemmar

Konsekvenser

Implementering

Klassen som använder algoritmen ( Context) inkluderar en abstrakt klass ( Strategy) som har en abstrakt metod som definierar hur algoritmen anropas. Varje härledd klass implementerar en obligatorisk version av algoritmen.

Замечание: метод вызова алгоритма не должен быть абстрактным, если требуется реализовать некотороин помечение.

Användbar information

Användning

Microsoft WDF- arkitekturen är baserad på detta mönster. Varje "drivrutin" och "enhet"-objekt har en oföränderlig del insydd i systemet, i vilken en föränderlig del (strategi) skriven i en specifik implementering registreras. Den föränderliga delen kan vara helt tom, vilket kommer att ge en drivrutin som inte gör något, men som samtidigt kan delta i PnP och energihantering.

ATL - biblioteket innehåller en uppsättning trådningsmodellklasser som är strategier (olika implementeringar av Lås / Lås upp, som sedan används av systemets huvudklasser). Dessa strategier använder dock statisk polymorfism genom en mallparameter snarare än dynamisk polymorfism genom virtuella metoder.

Exempel

Java exempel

Implementeringsexempel // Klassen som implementerar den specifika strategin måste implementera detta gränssnitt // Kontextklassen använder detta gränssnitt för att anropa det specifika strategigränssnittet Strategi { int execute ( int a , int b ) ; } // Implementera algoritmen med strategigränssnittsklassen ConcreteStrategyAdd implementerar Strategy { public int execute ( int a , int b ) { System . ut . println ( "kallas ConcreteStrategyAdd's execute()" ); returnera a + b ; // Lägg till med a och b } } class ConcreteStrategySubtract implementerar strategi { public int execute ( int a , int b ) { System . ut . println ( "Called ConcreteStrategySubtract's execute()" ); returnera a - b ; // Gör en subtraktion med a och b } } class ConcreteStrategyMultiply implementerar Strategi { public int execute ( int a , int b ) { System . ut . println ( "Kallad ConcreteStrategyMultiply's execute()" ); returnera a * b ; // Gör en multiplikation med a och b } } // Kontextklass som använder strategigränssnittsklassen Kontext { privat Strategistrategi ; _ // Konstruktör offentligt sammanhang () { } // Sätt ny strategi public void setStrategy ( Strategy strategy ) { this . strategi = strategi ; } public int executeStrategy ( int a , int b ) { returstrategi . _ exekvera ( a , b ); } } // Testapplikationsklass StrategiExempel { public static void main ( String [] args ) { Context context = new Context (); sammanhang . setStrategy ( ny ConcreteStrategyAdd ()); int resultatA = sammanhang . executeStrategy ( 3 , 4 ); sammanhang . setStrategy ( ny ConcreteStrategySubtract ()); int resultatB = sammanhang . executeStrategy ( 3 , 4 ); sammanhang . setStrategy ( ny ConcreteStrategyMultiply ()); int resultatC = kontext . executeStrategy ( 3 , 4 ); System . ut . println ( "Resultat A : " + resultat A ); System . ut . println ( "Resultat B: " + resultat B ); System . ut . println ( "Resultat C: " + resultat C ); } }

Exempel i C++

Implementeringsexempel #include <iostream> klass Strategi { offentliga : virtuell ~ Strategi () {} virtuell void användning () = 0 ; }; klass Strategi_1 : offentlig strategi { offentliga : void use (){ std :: cout << "Strategi_1" << std :: endl ; } }; klass Strategi_2 : offentlig strategi { offentliga : void use (){ std :: cout << "Strategy_2" << std :: endl ; } }; klass Strategi_3 : offentlig strategi { offentliga : void use (){ std :: cout << "Strategy_3" << std :: endl ; } }; klass sammanhang { skyddad : strategi * operation ; offentliga : virtuell ~ Kontext () {} virtual void useStrategy () = 0 ; virtual void setStrategy ( Strategy * v ) = 0 ; }; klass Klient : offentlig kontext { offentliga : void useStrategy () { operation -> använd (); } void setStrategy ( Strategi * o ) { operation = o ; } }; int main ( int /*argc*/ , char * /*argv*/ []) { Klient customClient ; strategi_1 str1 ; Strategi_2 str2 ; Strategi_3 str3 ; customClient . setStrategy ( & str1 ); customClient . useStrategy (); customClient . setStrategy ( & str2 ); customClient . useStrategy (); customClient . setStrategy ( & str3 ); customClient . useStrategy (); returnera 0 ; } Implementeringsexempel (mallparameter) #include <iostream> struct Strategi_1 { void use (){ std :: cout << "Strategi_1" << std :: endl ; }; }; struct Strategi_2 { void use (){ std :: cout << "Strategy_2" << std :: endl ; }; }; struct Strategi_3 { void use (){ std :: cout << "Strategy_3" << std :: endl ; }; }; mall < classOperation > _ struct Kund : offentlig verksamhet { void useStrategy () { detta -> använd (); } }; int main ( int /*argc*/ , char * /*argv*/ []) { Klient < Strategy_1 > customClient1 ; customClient1 . useStrategy (); Klient < Strategy_2 > customClient2 ; customClient2 . useStrategy (); Klient < Strategy_3 > customClient3 ; customClient3 . useStrategy (); returnera 0 ; }

Exempel i C#

Implementeringsexempel använder System ; namespace DesignPatterns.Behavioral.Strategy { // Klassen som implementerar den specifika strategin måste ärva detta gränssnitt // Kontextklassen använder detta gränssnitt för att anropa det särskilda strategins offentliga gränssnitt IStrategy { void Algorithm (); } // Första konkreta implementeringsstrategin. public class ConcreteStrategy1 : IStrategy { public void Algorithm () { Console . WriteLine ( "Strategialgoritm 1 körs." ); } } // Andra konkreta implementeringsstrategin. // Det kan finnas hur många implementeringar som helst. public class ConcreteStrategy2 : IStrategy { public void Algorithm () { Console . WriteLine ( "Strategialgoritm 2 körs." ); } } // Kontext som använder strategin för att lösa sitt problem. public class Context { // Referens till IStrategy-gränssnittet // låter dig automatiskt växla mellan specifika implementeringar // (med andra ord, detta är valet av en specifik strategi). privat IStrategy_strategy ; _ // Kontextkonstruktör. // Initierar objektet med strategin. offentlig kontext ( ISstrategistrategi ) { _strategy = strategi ; _ } // Metod för att sätta strategin. // Används för att ändra strategi under körning. // I C# kan det också implementeras som en postegenskap. public void SetStrategy ( IStrategy strategy ) { _strategy = strategy ; } // Någon kontextfunktionalitet som väljer // en strategi och använder den för att utföra sin uppgift. public void ExecuteOperation () { _strategy . algoritm (); } } // Applikationsklass. // Fungerar som en kontextklient i detta exempel. public static class Program { // <sammanfattning> // Programstartpunkt. // </summary> public static void Main () { // Skapa ett sammanhang och initiera det med den första strategin. Context context = new Context ( ny ConcreteStrategy1 ()); // Utför en kontextoperation som använder den första strategin. sammanhang . ExecuteOperation (); // Ersätt den första strategin med den andra i sammanhanget. sammanhang . SetStrategy ( ny ConcreteStrategy2 ()); // Utför kontextoperationen, som nu använder den andra strategin. sammanhang . ExecuteOperation (); } } }

Exempel i D

Implementeringsexempel import std . stdio ; gränssnitt IStrategy { int Action ( int a , int b ); } class TAddition : IStrategy { public int Action ( int a , int b ) { retur a + b ; } } klass TSubtraktion : IStrategy { public int Action ( int a , int b ) { retur a - b ; } } klass TContexet { privat : int a , b ; IStrategistrategi ; _ public : void SetAB ( int a , int b ) { TContexet . a = a ; TContexet . b = b ; }; void SetStrategy ( IStrategy strategy ) { TContexet . strategi = strategi ; } int Action ( ) { returstrategi . Åtgärd ( a , b ); } } void main () { TContexet context = new TContexet ; sammanhang . SetAB ( 10 , 5 ); sammanhang . SetStrategy ( ny TAddition ); writeln ( context.Action ( ) ); // femton sammanhang . SetStrategy ( ny TSubtraction ); writeln ( context.Action ( ) ); // 5 }

Exempel i Delphi

Implementeringsexempel program Strategy_pattern ; {$APPTYPE KONSOL} typ IStrategy = interface [ '{6105F24C-E5B2-47E5-BE03-835A894DEB42}' ] procedur Algoritm ; slut ; TConcreteStrategy1 = klass ( TInterfacedObject , IStrategy ) offentlig proceduralgoritm ; _ slut ; procedur TConcreteStrategy1 . algoritm ; börja Writeln ( 'TConcreteStrategy1.Algorithm' ) ; slut ; typ TConcreteStrategy2 = klass ( TInterfacedObject , IStrategy ) offentlig proceduralgoritm ; _ slut ; procedur TConcreteStrategy2 . algoritm ; börja Writeln ( 'TConcreteStrategy2.Algorithm' ) ; slut ; typ TContext = klass privat FStrategy : IStrategy ; offentligt förfarande ContextMethod ; egenskapsstrategi : IStrategy läs FStrategy skriv FStrategy ; _ slut ; procedur TContext . ContextMethod ; börja FStrategy . algoritm ; slut ; var Context : TContext ; börja Context := TContext . skapa ; prova Context . Strategi := TConcreteStrategy1 . skapa ; Sammanhang . ContextMethod ; Sammanhang . Strategi := TConcreteStrategy2 . skapa ; Sammanhang . ContextMethod ; äntligen Kontext . Gratis ; slut ; slut .

Javascript exempel

Implementeringsexempel // "gränssnitt"-strategi function Strategy () { detta . exec = funktion () {}; }; // implementera strategi // visa meddelandet i webbläsarens statusfält // (stöds inte av alla webbläsare) function StrategyWindowStatus () { this . exec = funktion ( meddelande ) { fönster . status = meddelande ; }; }; StrategyWindowStatus . prototyp = ny strategi (); StrategyWindowStatus . prototyp . konstruktor = StrategyWindowStatus ; // visa meddelande via popup // (kan blockeras av webbläsaren) funktion StrategyNewWindow () { this . exec = funktion ( meddelande ) { var win = fönster . open ( "" , "_blank" ); vinna . dokument . skriv ( "<html>" + meddelande + "</html>" ); }; }; StrategiNewWindow . prototyp = ny strategi (); StrategiNewWindow . prototyp . konstruktor = StrategiNewWindow ; // visa meddelande med modal fönsterfunktion StrategyAlert ( ) { this . exec = function ( meddelande ) { alert ( meddelande ); }; }; Strategivarning . prototyp = ny strategi (); Strategivarning . prototyp . konstruktor = Strategivarning ; // Sammanhang function Context ( strategi ) { detta . exec = funktion ( meddelande ) { strategi . exec ( meddelande ); }; } // Användning var showInWindowStatus = new Context ( new StrategyWindowStatus () ); var showInNewWindow = new Context ( new StrategyNewWindow () ); var showInAlert = new Context ( new StrategyAlert () ); showInWindowStatus . exec ( "meddelande" ); showInNewWindow . exec ( "meddelande" ); showInAlert . exec ( "meddelande" );

Exempel i PHP

Implementeringsexempel <?php - gränssnitt NamingStrategy { function createName ( $filnamn ); } class ZipFileNamingStrategy implementerar NamingStrategy { function createName ( $filename ) { return "http://downloads.foo.bar/ { $filename } .zip" ; } } class TarGzFileNamingStrategy implementerar NamingStrategy { function createName ( $filename ) { return "http://downloads.foo.bar/ { $filename } .tar.gz" ; } } function __construct ( NamingStrategy $strategy ) { $this -> namingStrategy = $strategy ; } function execute () { $url [] = $this -> namngivningsstrategi -> createName ( "Calc101" ); $url [] = $this -> namngivningsstrategi -> createName ( "Stat2000" ); returnera $url ; } } if ( strstr ( $_SERVER [ "HTTP_USER_AGENT" ], "Win" )) $kontext = ny kontext ( ny ZipFileNamingStrategy ()); else $context = new Context ( ny TarGzFileNamingStrategy ()); $kontext -> exekvera (); ?>

Exempel i Python 2.7

Implementeringsexempel klass Människor ( objekt ): verktyg = Ingen namn = namn def setTool ( själv , verktyg ): själv . verktyg = verktyg verktyg . skriva ( själv . namn , text ) class ToolBase : """ `Writing Tool` Algoritmfamilj """ def write ( self , name , text ): raise NotImplementedError () klass PenTool ( ToolBase ): """Penna""" def skriv ( själv , namn , text ): skriv ut ' % s (penna) %s ' % ( namn , text ) class BrushTool ( ToolBase ): """Brush""" def write ( själv , namn , text ): skriv ut u ' %s (med pensel) %s ' % ( namn , text ) klass Student ( Människor ): """Student""" verktyg = PenTool () klass Målare ( Människor ): """Artist""" verktyg = BrushTool () skriv ( u 'Jag skriver en föreläsning om strategimönstret' ) # Maxim (med en penna) Jag skriver en föreläsning om strategimönstret sasha = Målare ( u 'Sasha' ) sasha . setTool ( PenTool ()) sasha . skriv ( u 'Nej, jag skulle hellre skriva en synopsis' ) # Sasha (med en penna) Nej, jag skulle hellre skriva en synopsis

Exempel i Ruby

Implementeringsexempel kräver "gränssnitt" strategi = gränssnitt { required_methods :use } class StrategyOne def use sätter "Strategy one" end implementerar Strategy end klass StrategyTwo def användning sätter "Strategi två" slutet implementerar Strategi slut klass StrategyThree def användning sätter "Strategi tre" slutet implementerar Strategi slut klass Kontext attr_accessor : strategi def initialisera strategi @strategy = strategi slut def användningStrategistrategi . använd slutänden _ ny strategi ett . nytt sammanhang . använd Strategi sammanhang . strategi = strategi två . nytt sammanhang . använd Strategi sammanhang . strategi = StrategyThree . använd Strategi

Informationskällor

  • E. Gamma, R. Helm, R. Johnson, J. Vlissides . Tekniker för objektorienterad design. Designmönster = Designmönster: Element av återanvändbar objektorienterad programvara. - St Petersburg. : "Peter" , 2007. - S. 366. - ISBN 978-5-469-01136-1 . (även ISBN 5-272-00355-1 )
  • Shalloway , Alan, Trott , James, R. Designmönster. Ett nytt förhållningssätt till objektorienterad analys och design : Per. från engelska. -M .: Williams Publishing House, 2002. -288 sid. ISBN 5-8459-0301-7
  • Grand, M. Designmönster i Java: Per. från engelska .. - M . : New knowledge, 2004. - S. 559. - ISBN 5-94735-047-5 .