Strategy

Przeznaczenie

  • Definiuje rodziny algorytmów

  • Dokonuje ich hermetyzacji i sprawia, że stają się one wymienne

  • Pozwala na modyfikację danego algorytmu niezależnie od klienta, który tego algorytmu używa

Kontekst

  • Wiele powiązanych ze sobą klas różni się tylko zachowaniem

  • Potrzebne są różne warianty jakiegoś algorytmu

  • W algorytmie są używane dane, o których klient nie powinien wiedzieć – Strategia pozwala uniknąć ujawniania złożonych i specyficznych dla algorytmu struktur danych

  • Klasa definiuje wiele zachowań, które w operacjach są uwzględnione w postaci wielokrotnych instrukcji warunkowych

Problem

  • Chcemy dokonać hermetyzacji algorytmu w klasie i stosując składanie obiektów umożliwić wymianę implementacji algorytmu

Struktura

_images/Strategy.png

Uczestnicy

Strategy

  • deklaruje interfejs wspólny dla wszystkich obsługiwanych algorytmów

  • obiekt Context wykorzystuje ten interfejs do wykonywania algorytmu zdefiniowanego przez klasę ConcreteStrategy

ConcreteStrategy – implementuje algorytm, wykorzystując interfejs klasy Strategy

Context

  • jest konfigurowany za pomocą obiektu ConcreteStrategy

  • utrzymuje odwołanie do obiektu typu Strategy

  • może definiować interfejs umożliwiający obiektowi strategii uzyskanie dostępu do jego danych

Współpraca

  1. Strategy i Context współdziałają w celu zaimplementowania wybranego algorytmu.

  2. Klienci tworzą obiekt klasy ConcreteStrategy i przekazują go do kontekstu.

  3. Kontekst przekazuje żądania od klientów do swojej strategii.

  4. Klienci komunikują się wyłącznie z kontekstem.

  5. Komunikacja między obiektami kontekstu i strategii:

  • w chwili wywołania kontekst może przekazać strategii wszystkie dane potrzebne do realizacji tego algorytmu,

  • kontekst przekazuje samego siebie jako argument – umożliwia to obiektowi Strategy zwrotne odwołanie się w miarę potrzeby do kontekstu.

Konsekwencje

  1. Rodziny powiązanych ze sobą algorytmów. Hierarchie podklas Strategy definiują rodzinę algorytmów do wielokrotnego użycia przez konteksty.

  2. Alternatywa dla tworzenia klas pochodnych. Enkapsulacja algorytmu w oddzielnych klasach umożliwia modyfikowanie go niezależnie od jego kontekstu – ułatwia to zmienianie go, zrozumienie go i rozszerzanie.

  3. Strategie eliminują instrukcje warunkowe. Alternatywa dla stosowania instrukcji warunkowych w celu wybrania pożądanego zachowania.

  4. Wybór implementacji. Zapewnienie różnych implementacji tego samego zachowania.

  5. Klienci muszą być świadomi istnienia różnych strategii i różnic pomiędzy nimi – potencjalna wada.

  6. Wyższe koszty związane z komunikacją między strategią a kontekstem.

  7. Zwiększona liczba obiektów.

Implementacja

Definiowanie interfejsów strategii (Strategy) i kontekstu (Context). Interfejsy Strategy i Context muszą umożliwić konkretnej implementacji strategii (ConcreteStrategy) dostęp do dowolnych danych, jakich będzie ona potrzebować z kontekstu (i vice versa):

  1. Context przesyła dane do operacji Strategy w argumentach

  2. Context przesyła siebie samego jako argument, a strategia jawnie żąda danych od kontekstu

Klasa kontekstu jest prostsza w użyciu, jeżeli użycie jej bez obiektu strategii ma sens. Implementacja strategii domyślnej – klienci nie muszą zajmować się obiektami strategii. Jeśli strategie są prostymi metodami, można zrezygnować z enkapsulacji w postaci odrębnej klasy na rzecz wskaźników do funkcji lub obiektów funkcyjnych.

Podsumowanie

  1. Obiekt klasy Strategy hermetyzuje algorytm w postaci obiektu.

  2. Program wykorzystujący wzorzec Strategy może oferować wiele wersji algorytmu lub zachowania.

  3. Zachowanie obiektów może się dynamicznie zmieniać w czasie wykonywania programu.

  4. Delegowanie zachowania do interfejsu Strategy uniezależnia klasy korzystające z tego interfejsu od klas, które implementują zarówno ten interfejs, jak i właściwe zachowanie.