Návrhové vzory (design patterns) - diplomová práce M. Dvořáka
Command Pattern
SKUPINA: Behavioral Patterns
Problém
Odstínění klienta od procesu zpracování jeho požadavku. Klient pouze definuje požadavek a určí zpracovatele, ale už se nezajímá o způsob a čas vykonání jeho požadavku.
Podmínky
Tento návrhový vzor umožní klientu vytvořit požadavek jako objekt implementující dané rozhraní. Při vytváření požadavku dochází k jeho parametrizaci. Tímto způsobem lze modifikovat vykonání příkazu bez ovlivnění klienta, který pouze vytváří požadavek podle dohodnuté struktury. Pro klienta tvoří Command černou skříňku, o které neví jakým způsobem je implementováno její chování. Jelikož každý požadavek (Command) implementuje stejné rozhraní, je znám způsob zahájení jeho zpracování.
Řešení

Objekt Client vytváří požadavek Concrete Command a specifikuje jeho zpracovatele Receiver, který bude daný požadavek vykonávat. Každý Concrete Command zahrnuje implementaci metody execute, která je definována v obecném rozhraní Command a umožňuje spustit začátek zpracování příkazu. V této metodě jsou volány metody zpracovatele například action. Jako Receiver může být použita jakákoliv třída.
Invoker „skladuje“ jednotlivé Concrete Command objekty a vyvolává na nich metodu execute. Invoker může odložit vykonání požadavku v případě, že nejsou v systému dostupné například potřebné zdroje, nebo se čeká na dokončení zpracování jiných požadavků. Jestliže není příkaz vykonáván hned, dochází k jeho zařazení do fronty. Pokud se jedná o operaci, u které je nutné zajistit možnost jejího odvolání, uchovává Concrete Command stav před jejím vykonáním, aby bylo možné s k tomuto stavu vrátit.
Příklad
V našem příkladě dodání zeleniny a ovoce budeme předpokládat, že maloobchody si vytvářejí objednávky na zboží a zasílají je velkoobchodu. Každá objednávka implementuje rozhraní Objednávka, kde je definován sklad, který bude zboží fyzicky dodávat. Vytvořená objednávka je zasílána Velkoobchodu. Ten zkontroluje bonitu zákazníka a zařadí objednávku do fronty. Postupně jsou jednotlivé požadavky zpracovávány voláním metody Execute(), která provádí přesměrování zpracování požadavku na maloobchodem určený sklad (metoda Zpracuj objednávku()).

Výsledek
Command Pattern odděluje objekty, jež vyvolávají požadavek, od objektu, který zná, jak daný úkol zpracovat. Aby bylo možné tyto dva objekty oddělit, je vytvořeno abstraktní rozhraní, které umožňuje svázat požadavek s jeho zpracovatelem.
Odůvodnění a souvislosti
Vytvořením požadavku jako objektu je možné parametrizovat chování klienta bez toho, aniž by musel být změněn. Je možné měnit konkrétní požadavky upravením metody execute, která je volána.
Command objekt zapouzdřující požadavek má svůj vlastní životní cyklus, který není určován tímto požadavkem. Během životního cyklu může být objekt uschován do trvalé paměti, opět vyvolán nebo zařazen do fronty. Implementaci této logiky obvykle zahrnuje objekt Invoker, který může zajišťovat vzájemnou posloupnost vykonávání příkazů.
Častým přístupem pro použití tohoto návrhového vzoru jsou „undo-redo“ operace. Command pattern si může uchovat dostatek informací před voláním metody execute, aby byl schopen nastolit zpět výchozí stav. Zapouzdřením takové funkčnosti přímo do objektu Command výrazně zjednoduší architekturu výsledného systému.
Command objekt může podporovat logování, aby bylo možné jej znovu obnovit v případě selhání systému a spustit. Tímto je možné využít Command pattern například v transakčních systémech.
Související vzory
- Template Method - může být využít k implementaci logiky zpětných operací.
- Chain of Responsibility - v tomto vzoru může být požadavek zapouzdřen pomocí Command pattern do objektu.
- Memento - jako Command pattern představuje způsob uchování určité skutečnosti a její vyvolání v pozdějším čase. Na rozdíl od Commandu se nejedná o požadavek, ale vnitřní stav. Command může použít Memento k správě informací důležitých pro návrat ke stavu před vykonáním příkazu.
Reference
- Swing - pomocí návrhového vzoru jsou v této knihovně zajištěny undo/redo operace.
- Vytváření položek menu - jednoduchým příkladem použití tohoto vzoru je vytváření položek menu aplikace. Jednotlivé položky, které lze implementovat pomocí javax.swing.JMenuItem, zachycují jejich zvolení uživatelem. Každá položka by měla mít referenci na objekt, který bude zpracovávat požadavky od klienta. Tyto položky už tedy neřeší věcnou logiku vyřízení požadavku od uživatele, ale pouze spustí metodu actionPerformed objektu, který je u nich registrována jako Listener. Tento objekt řeší věcnou logiku splnění požadavku, který vyplývá ze zvolení položky menu.
