Wzorce projektowe – Strategia
Strategia jest jednym z popularniejszych wzorców projektowych i może być stosowana wszędzie tam, gdzie jest konieczna implementacja kilku różnych wersji algorytmów, realizujących ten sam lub podobny typ zadania. Każdy z tych algorytmów jest nazywana strategią, która następnie jest używana lub zmieniana przez klienta.
Charakterystyka wzorca strategia
Zadaniem wzorca Strategia (Strategy) jest zdefiniowanie w oddzielnych klasach grup algorytmów z danej rodziny. Taka konstrukcja kodu powoduje możliwość wymiennego użycia tych algorytmów (również w trakcie działania aplikacji), ułatwia rozszerzanie funkcjonalności, ogranicza użycie instrukcji warunkowych oraz ułatwia testowanie poszczególnych rozwiązań algorytmów.
Poniższy diagram UML pokazuje podstawową strukturę wzorca strategii. Poszczególne wersje algorytmu realizowane są za pomocą osobnych klas, które implementują wspólny interfejs. Następnie tak przygotowany program, użyty jest w klasie kontekstowej.
Przykład zastosowania wzorca strategia – kompresor plików
Artykuł ten omawia wzorzec strategii na prostym przykładzie w języku PHP. Skrypt będzie realizował zadanie kompresji pliku. Klient będzie mógł wybrać strategię kompresji.
W pierwszej kolejności zdefiniujmy interfejs systemu kompresji, który dla uproszczenia będzie posiadał tylko jedną metodę kompresowania pliku.
1 2 3 4 5 6 |
namespace DesignPatterns\Strategy\Compression; interface Compression { public function compressFile($filePath); } |
Następnie zdefiniujmy konkretne klasy kompresji, implementujące interfejs.
1 2 3 4 5 6 7 8 9 10 |
namespace DesignPatterns\Strategy\Compression; use DesignPatterns\Strategy\Compression\Compression; class ZipCompression implements Compression { public function compressFile($filePath) { echo 'Kompresuje plik '.$filePath.' do formatu ZIP'; } } |
1 2 3 4 5 6 7 8 9 10 |
namespace DesignPatterns\Strategy\Compression; use DesignPatterns\Strategy\Compression\Compression; class RarCompression implements Compression { public function compressFile($filePath) { echo 'Kompresuje plik '.$filePath.' do formatu RAR'; } } |
Powyższe skrypty są oczywiście tylko przykładem i nie realizują faktycznej funkcjonalności kompresji plików, ponieważ nie jest to tematem tego artykułu. Pokazują jedynie strukturę programu opartego na omawianym wzorcu projektowym.
Ostatnim elementem przykładu jest napisanie klasy ustawiającej i realizującej wybraną strategię (tzw. kontekst).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
namespace DesignPatterns\Strategy\Compression; class CompressionSystem { private $compressionStrategy; public function setCompressionEngine(Compression $compressionStrategy) { $this->compressionStrategy = $compressionStrategy; } public function compress($filePath) { $this->compressionStrategy->compressFile($filePath); } } |
Użycie tak napisanego program jest banalnie proste. Wystarczy ustawić wybraną strategię i wywołać odpowiednią funkcję.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
require_once '../../../vendor/autoload.php'; use DesignPatterns\Strategy\Compression\CompressionSystem; use DesignPatterns\Strategy\Compression\ZipCompression; use DesignPatterns\Strategy\Compression\RarCompression; $compressionSystem = new CompressionSystem(); $compressionSystem->setCompressionEngine(new ZipCompression()); $compressionSystem->compress('plik-archiwalny-1.ods'); $compressionSystem->setCompressionEngine(new RarCompression()); $compressionSystem->compress('plik-archiwalny-2.ods'); |
Wynikiem działania powyższego skryptu jest uruchomienia funkcji kompresującej pliki do wersji ZIP I RAR.
1 2 |
Kompresuje plik plik-archiwalny-1.ods do formatu ZIP Kompresuje plik plik-archiwalny-2.ods do formatu RAR |
Powyższy przykład można pobrać tutaj: compression-strategy
Przykład na GitHub: https://github.com/molitorys/design-patterns/tree/master/src/Strategy/Compression
Podsumowanie
Wzorzec strategii umożliwia porządkuje kod aplikacji. Umożliwia rozdzielenie poszczególnych części programu, ułatwia jego utrzymanie, zmiany i rozszerzanie o nowe wersje.