Návrhové vzory (design patterns) - diplomová práce M. Dvořáka
Chain Of Responsibility Pattern
SKUPINA: Behavioral Patterns
Problém
Jak zaslat požadavek bez přesného vymezení objektu, který jej zpracuje.
Podmínky
Existuje několik instancí různých tříd, které mohou potenciálně zpracovat požadavek. Klient jej odesílá bez přesného určení konkrétní instance. Třídy musí implementovat stejné rozhraní.
Řešení

Handler představuje rozhraní pro třídy, jejichž instance jsou potenciálními zpracovateli požadavku. Klient má referenci na jednu konkrétní instanci, které zasílá požadavek. Tato je začátkem řetězu objektů, které mohou zpracovat daný úkol. Jestliže první instance může požadavek vyřídit, učiní tak a tím ukončí jeho zpracování. Jestliže instance není vhodná pro vyřízení požadavku, je tento odeslán jinému objektu, který je další části v řetězu. Každá instance vlastní referenci na následující objekt v řetězu. Požadavek putuje řetězem do doby, než některá část řetězu jej zpracuje. Jelikož jazyk Java neobsahuje možnosti dědění z více tříd, je lepší použít rozhraní než abstraktní třídu pro definování Handleru.
Příklad
V našem příkladě bychom mohli uvažovat dodavatelskou síť s několika velkoobchody a sklady. Každý z velkoobchodů může využívat všechny možné sklady pro získání dodávky ovoce. Všechny sklady implementují rozhraní Sklad, ve kterém je definována metoda pro objednání určitého ovoce velkoobchodem - Dodej ovoce (Druh). Toto rozhraní je ukázkou Handleru a je deklarováno všemi sklady zapojenými v síti. Sklady 1–3 tvoří řetěz vyřizující požadavek. Uspořádání řetězu je možné například na základě vzdálenosti od velkoobchodu, kdy nejbližší sklad zpracovává požadavek jako první. Jestliže není daný druh ovoce v jeho evidenci, je požadavek zasílán dalšímu článku řetězu. Reference na další sklad je uložena v položce Následující. Výhodou tohoto řetězu je jeho snadné přizpůsobení, když dojde k přestěhování velkoobchodu a tím k změně vzdáleností ke skladům. V takovém případě je nutné pouze změnit pořadí skladu v řetězci, a tím určit prioritu vyřizování požadavků.

Výsledek
Byl vytvořen řetěz, který umožňuje předávat požadavek mezi instancemi. Klient potřebuje pouze znát vstupní body. Může existovat pouze jeden vstupní bod do řetězu, ale i více těchto vstupů. Druhý přístup je možné využít například, jestliže jsou objekty uspořádány do stromové struktury. Můžeme si například představit Help systém, kde se postupuje od konkrétnějších tříd k obecnějším. Například při stisku F1 se nejprve požadovanou zprávu snaží najít funkce, která je právě vykonávána. Jestliže namůže najít žádnou nápovědu, předává požadavek obecnější funkci, která může poskytnout již pouze nápovědu na vyšší úrovni. Takto může být požadavek předáván do vyšších vrstev Help systému, až skončí u základních informací o aplikaci, které jsou zobrazeny v případě neúspěchu hledání konkrétní nápovědy.
Odůvodnění a souvislosti
Použití tohoto návrhového vzoru je vhodné v těchto situacích:
- Existuje více objektů, jež mohou zpracovávat požadavek a není možné určit konkrétní objekt pro jeho vyřízení.
- Je nutné poslat požadavek skupině objektů, které již sami řeší, kdo požadavek zpracuje.
- Chceme dynamicky měnit skupinu objektů, které mohou zpracovávat požadavek.
Návrhový vzor je používán především ke snížení závislosti mezi klientem a objektem, který bude zpracovávat daný požadavek. Dynamicky je možné měnit řetěz podle situace. Další vlastností tohoto vzoru je možnost neexistence žádného objektu, který požadavek zpracuje. V takovém případě je nutné tento stav ošetřit, protože jinak je požadavek zničen na konci řetězu.
Je to jedna z technik “propagace”, tj. přenášení požadavků z kontejneru na obsažené objekty. Druhou technikou je to, že některé objekty z řetězce přispívají svou částí k celkovému řešení. Třetí technikou je přímá adresace objektů z řetězce.
Související vzory
- Composite - jestliže řetěz objektů, využívaný tímto vzorem, je částí rozsáhlejší struktury, je tato obvykle vytvořena pomocí Composite vzoru.
- Command - představuje odlišný způsob. Jestliže Chain of Responsibility zajišťuje způsob nespecifikování konkrétního příjemce požadavku, Command tento objekt určuje přesně.
- Template Method - je využíván k řízení chování jednotlivých objektů ve struktuře, které je vytvořena pomocí Composite.
Reference
- Nejzákladnějším příkladem využití tohoto návrhového vzoru je princip dědičnosti v objektových programovacích jazycích. Jestliže je volána funkce třídy, která tuto funkci neobsahuje, dochází k hledání funkce ve třídách, z kterých je zděděna.
- Návrhový vzor je použit ve webovém serveru Tomcat jakarta.apache.org/tomcatpovolené sítě, kde servlet API a požadavky jsou vyřizovány pomocí řetězu tvořeného Interceptory.
- Ve verzi Java 1.0 byl systém zasílání událostí v knihovně AWT implementován podle tohoto návrhového vzoru.
- Dalším příkladem z jazyka Java je odchytávání výjimek. Jestliže dojde k vyvolání výjimky, je hledán „try/catch“ blok, který deklaruje zpracování této výjimky. Hledání takového bloku se začíná na nejnižší úrovni a v případě nenalezení je výjimka propagována směrem nahoru.
