IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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í.

Návrhový vzor Chain of responsibility z GOF - GOF - Vzory správania

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

 

Všetky články v sekcii
GOF - Vzory správania
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity