Chain of responsibility
Chain of responsibility je návrhových vzor umožňujúci oddelenie odosielateľa požiadavky od jeho príjemcov, ktorých môže byť viac. Požiadavka je odovzdávaný medzi príjemcami až k tomu, ktorý je kompetentný ho vybaviť. Implementácia by mala počítať aj so situáciou, kedy tento príjemca nebude nájdený.
Motivácia
Ak by sme napevno spojili triedu, ktorá posiela nejaký požiadavku, a triedu, ktorá ho spracováva, porušili by sme low coupling. Tiež by sme prišli o možnosť napojenia na viacerých handler, ktoré požiadavku spracúvajú. Toho sa v praxi často využíva pri aplikovaní rôznych filtrov, ktoré sú v reťazi za sebou a požiadavku postupne nejako spracovávajú.
Použitie nie je obmedzené len na lineárnej dátovej štruktúry, ale odovzdávanie zodpovednosti môže prebiehať aj na úrovni k rodičovi v stromových štruktúrach. Niekedy býva vzor kombinovaný so vzorom Composite, ktorý definuje najefektívnejší spôsob ako také stromovej štruktúry vytvárať. Na takýto strom niekedy môže byť zaznamenané ako na Tree of responsibility. Niektoré frameworky používajú Chain of responsibility na implementáciu událostního modelu.
Vzor
Asi vás neprekvapí, že Handler
, príjemca požiadavke, je tu
definovaný ako rozhranie. S týmto rozhraním komunikuje odosielateľ
požiadavke a implementujú ho jednotlivé handlermi požiadavke v reťazi alebo
stromu. Tie sú spolu prepojené pomocou referencií.
Handler typicky poskytuje metódy pre nastavenie ďalšieho handler. Ďalej metódu pre vybavenie požiadavky, táto je polymorfné. A nakoniec pre odovzdanie požiadavky ďalšiemu handler. To môže prebehnúť aj keď bola požiadavka spracovaný čiastočne alebo vôbec, napr. Pretože je handler zaneprázdnený alebo nie je pre spracovanie danej požiadavky kompetentní.
Príklad
Na chain of responsibility sa dá vymyslieť určite plno príkladov, pretože týmto spôsobom funguje veľké množstvo služieb. Keď si napríklad. Objednávate tovar z cudziny, vašu požiadavku vybaví reťaz hneď niekoľkých pôšt. Reálne praktické použitie však spravidla býva v implementácii nejakých filtrov. Tie sú pospájané za sebou a požiadavku pohltí v prípade, že nie je žiaduce. Až posledný článok takéhoto reťazca požiadavka vybaví.
Vytvorme si ukážku reťaze takýchto filtrov na požiadavku na prijatie emailu, ktorý najprv poputuje spamfilter, potom nejakým užívateľským filtrom, a až potom sa potenciálne dostane k handler, ktorý ho vloží do prichádzajúcej pošty. Ďalšie handler môže vyvolať upozornenie na nový email. Urobme si príklad prijatie emailu, ktorý proputuje niekoľkými filtrami. Tie bude možné ľubovoľne pridávať a meniť práve vďaka vzoru.
Definujme abstrakciu pre handlermi v reťaze:
public abstract class HandlerPozadavku { private HandlerPozadavku dalsi; public HandlerPozadavku setDalsi(HandlerPozadavku dalsi) { this.dalsi = dalsi; return dalsi; } protected void nechVyriditDalsiho(Pozadavek pozadavek) { if (dalsi != null) dalsi.vyridPozadavek(pozadavek); } public abstract void vyridPozadavek(); }
Všimnite si, že metóda setDalsi()
vracia ďalší handler v
reťazi. To je preto, aby sme mohli pomocou Method
Chaining rovno poskladať celý reťaz. Napr. takto:
spamFiltr.setDalsi(uzivatelskyFiltr).setDalsi(prichoziPostaHandler);
Reťaz môžeme jednoducho pospájať na jedinom riadku. Nasleduje možná podoba konkrétnych handler:
public class SpamFiltr extends HandlerPozadavku { public void vyridPozadavek(Pozadavek pozadavek) { if (!pozadavek.Email.Text.Contains("free pills")) { // Jednoduchý spamfiltr nechVyriditDalsiho(pozadavek); } } } public class UzivatelskyFiltr extends HandlerPozadavku { public List<String> zakazaneAdresy = new ArrayList<String>(); public void vyridPozadavek(Pozadavek pozadavek) { if (!zakazaneAdresy.contains(pozadavek.email.adresa)) { // Jednoduchý uživatelský filtr nechVyriditDalsiho(pozadavek); } } } public class PrichoziPostaHandler extends HandlerPozadavku { private PrichoziPosta posta; public PrichoziPostaHandler(PrichoziPosta posta) { this.posta = posta; } public void VyridPozadavek(Pozadavek pozadavek) { posta.pridej(pozadavek.email); } }
Funkčnosti jednotlivých filtrov sú samozrejme extrémne zjednodušené a
len ilustratívne. Celý reťaz by sme dali do pohybu odovzdaním požiadavke
jeho prvému článku, ktorým je SpamFiltr
.
Súvisiace vzory
- Composite - Chain of responsibility možno aplikovať okrem lineárnych štruktúr aj na štruktúry stromovej, ktorých návrh rieši vzor composite