Strategy

Situace

Pro řešení daného problém existuje několik různých algoritmů, které mají stejné rozhraní (vstup i výstup). Klient má být od konkrétního algoritmu odstíněn, ale může ovlivnit, jaký algoritmus se použije.

Problém

Implementace různých algoritmů pro řešení jednoho problému si přímo říká o jejich zobecnění na úrovni vstupu a výstupu. Tak budou algoritmy vzájemně zaměnitelné a klient bude mít možnost zvolit takový algoritmus, který mu v danou chvíli nejlépe vyhovuje. Někdy například bude výhodnější použít pomalejší algoritmus nenáročný na paměť, jindy ten nejrychlejší možný, a to bez ohledu na použité prostředky. Odstíněním klienta od konkrétního algoritmu se zvýší vzájemná nezávislost jednotlivých součástí systému.

Řešení

Vstup a výstup algoritmů se zobecní a extrahuje do rozhraní. Toto rozhraní bude implementováno několika třídami, přičemž každá z těchto tříd představuje právě jeden algoritmus. Odstínění klienta od konkrétního algoritmu zajistí další třída, která bude uchovávat zvolený algoritmus a delegovat na něj všechny potřebné požadavky od klienta.

Varianty
  • třída s algoritmem zvolí konkrétní algoritmus sama na základě parametrů
  • konkrétní algoritmus se předává v konstruktoru
  • konkrétní algoritmus lze nastavit speciální metodou (setterem)
UML diagramy

diagram tříd

Související vzory
  • State – vnitřní stav ovlivňuje klient pouze nepřímo
Příklad

Následuje jednoduchý příklad implementace tohoto vzoru v programovacím jazyce Java.

Strategie

Násobení dvou čísel lze implementovat různě. V příkladu jsou to způsoby dva: standardní násobení a postupné sčítání. Oba způsoby výpočtu implementují stejné rozhraní, protože jsou volně zaměnitelné.

kód v jazyce Java - Zobrazit

  1. /**
  2.  * Strategie pro násobení dvou čísel.
  3.  *
  4.  * @author Vojtěch Hordějčuk
  5.  */
  6. public interface Strategy
  7. {
  8.   /**
  9.    * Vynásobí dvě čísla.
  10.    *
  11.    * @param a
  12.    * činitel
  13.    * @param b
  14.    * činitel
  15.    * @return součin
  16.    */
  17.   public int multiply(int a, int b);
  18. }
  19.  
  20. /**
  21.  * Standardní implementace násobení.
  22.  *
  23.  * @author Vojtěch Hordějčuk
  24.  */
  25. public class TimesStrategy implements Strategy
  26. {
  27.   @Override
  28.   public int multiply(int a, int b)
  29.   {
  30.     return a * b;
  31.   }
  32. }
  33.  
  34. /**
  35.  * Implementace násobení pomocí sčítání.
  36.  *
  37.  * @author Vojtěch Hordějčuk
  38.  */
  39. public class PlusStrategy implements Strategy
  40. {
  41.   @Override
  42.   public int multiply(int a, int b)
  43.   {
  44.     int i = Math.abs(b);
  45.     int r = a;
  46.  
  47.     while (i > 1)
  48.     {
  49.       r += a;
  50.       i--;
  51.     }
  52.  
  53.     return (b < 0) ? -r : r;
  54.   }
  55. }
Kontext

Kontext uchovává zvolenou strategii.

kód v jazyce Java - Zobrazit

  1. /**
  2.  * Kontext obsahující strategii.
  3.  *
  4.  * @author Vojtěch Hordějčuk
  5.  */
  6. public class Context
  7. {
  8.   /**
  9.    * aktivní strategie
  10.    */
  11.   private Strategy strategy;
  12.  
  13.   /**
  14.    * Vytvoří novou instanci.
  15.    *
  16.    * @param strategy
  17.    * zvolená strategie
  18.    */
  19.   public Context(Strategy strategy)
  20.   {
  21.     this.strategy = strategy;
  22.   }
  23.  
  24.   /**
  25.    * Vynásobí dvě čísla.
  26.    *
  27.    * @param a
  28.    * činitel
  29.    * @param b
  30.    * činitel
  31.    * @return součin
  32.    */
  33.   public int multiply(int a, int b)
  34.   {
  35.     return strategy.multiply(a, b);
  36.   }
  37. }
Test

Násobení dvou čísel se provede dvakrát, pokaždé s jinou strategií. V obou případech by měl být výsledek stejný, a to i přesto, že byly použité dva naprost odlišné algoritmy. Klient nemusí vědět o tom, jak algoritmy pracují.

kód v jazyce Java - Zobrazit

  1. public static void main(String[] args)
  2. {
  3.   // test první strategie
  4.  
  5.   Context context1 = new Context(new TimesStrategy());
  6.   int r1 = context1.multiply(3, 5);
  7.   System.out.println(r1); // 3*5 = 15
  8.  
  9.   // test druhé strategie
  10.  
  11.   Context context2 = new Context(new PlusStrategy());
  12.   int r2 = context2.multiply(3, 5);
  13.   System.out.println(r2); // 3*5 = 3+3+3+3+3 = 15
  14. }

Reference