Reťazec zodpovednosti Návrhový vzor v Jave

1. Úvod

V tomto článku sa pozrieme na široko používané vzor správania: Reťaz zodpovednosti.

Viac dizajnových vzorov nájdeme v našom predchádzajúcom článku.

2. Reťaz zodpovednosti

Wikipedia definuje Chain of Responsibility ako návrhový vzor pozostávajúci zo „zdroja príkazových objektov a série objektov na spracovanie“.

Každý objekt spracovania v reťazci je zodpovedný za určitý typ príkazu a spracovanie je hotové, tento príkaz sa pošle ďalšiemu procesoru v reťazci.

Vzor reťazca zodpovednosti je vhodný pre:

  • Odpojenie odosielateľa a príjemcu príkazu
  • Výber stratégie spracovania v čase spracovania

Pozrime sa teda na jednoduchý príklad vzoru.

3. Príklad

Pomocou reťazca zodpovednosti vytvoríme reťazec na spracovanie požiadaviek na autentizáciu.

Poskytovateľom autentifikácie vstupu bude teda server príkaza každý autentifikačný procesor bude samostatný procesor objekt.

Najprv si vytvoríme abstraktnú základnú triedu pre naše procesory:

verejná abstraktná trieda AuthenticationProcessor {public AuthenticationProcessor nextProcessor; // štandardné konštruktory public abstract boolean isAuthorized (AuthenticationProvider authProvider); }

Ďalej vytvoríme konkrétne procesory, ktoré sa rozširujú AuthenticationProcessor:

verejná trieda OAuthProcessor rozširuje AuthenticationProcessor {public OAuthProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override public boolean isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof OAuthTokenProvider) {return true; } else if (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } return false; }}
verejná trieda UsernamePasswordProcessor rozširuje AuthenticationProcessor {public UsernamePasswordProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override public boolean isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof UsernamePasswordProvider) {return true; } else if (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } return false; }}

Tu sme vytvorili dva konkrétne procesory pre naše prichádzajúce žiadosti o autorizáciu: UsernamePasswordProcessor a OAuthProcessor.

Pre každú z nich sme preťažili jeAutorizovaný metóda.

Teraz vytvorme niekoľko testov:

verejná trieda ChainOfResponsibilityTest {private static AuthenticationProcessor getChainOfAuthProcessor () {AuthenticationProcessor oAuthProcessor = nový OAuthProcessor (null); vrátiť nový UsernamePasswordProcessor (oAuthProcessor); } @Test public void givenOAuthProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertTrue (authProcessorChain.isAuthorized (nový OAuthTokenProvider ())); } @Test public void givenSamlProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertFalse (authProcessorChain.isAuthorized (nový SamlTokenProvider ())); }}

Vyššie uvedený príklad vytvára reťazec autentifikačných procesorov: UsernamePasswordProcessor -> OAuthProcessor. V prvom teste je autorizácia úspešná a v druhom zlyhá.

Najprv, UsernamePasswordProcessor skontroluje, či je poskytovateľ autentifikácie inštanciou UsernamePasswordProvider.

To nie je očakávaný vstup, UsernamePasswordProcessor delegáti na OAuthProcessor.

Posledný OAuthProcessor spracuje príkaz. V prvom teste je zhoda a test vyhovuje. V druhej už v reťazci nie sú žiadne ďalšie procesory a výsledkom je zlyhanie testu.

4. Princípy implementácie

Pri implementácii reťazca zodpovednosti musíme mať na pamäti niekoľko dôležitých zásad:

  • Každý procesor v reťazci bude mať implementáciu na spracovanie príkazu
    • V našom príklade vyššie majú všetky procesory implementáciu jeAutorizovaný
  • Každý procesor v reťazci by mal mať odkaz na nasledujúci procesor
    • Vyššie, UsernamePasswordProcessor delegáti na OAuthProcessor
  • Každý procesor je zodpovedný za delegovanie na ďalší procesor, takže dávajte pozor na zrušené príkazy
    • Opäť v našom príklade, ak je príkaz inštanciou SamlProvider potom sa žiadosť nemusí spracovať a bude neoprávnená
  • Procesory by nemali vytvárať rekurzívny cyklus
    • V našom príklade nemáme v našom reťazci cyklus: UsernamePasswordProcessor -> OAuthProcessor. Ale ak to výslovne nastavíme UsernamePasswordProcessor ako ďalší procesor z OAuthProcessor, potom skončíme s cyklom v našom reťazci: UsernamePasswordProcessor -> OAuthProcessor -> UsernamePasswordProcessor. Pomôcť vám s tým môže ďalší procesor v konštruktore
  • Daný príkaz spracuje iba jeden procesor v reťazci
    • V našom príklade, ak prichádzajúci príkaz obsahuje inštanciu OAuthTokenProvider, potom iba OAuthProcessor príkaz zvládne

5. Využitie v skutočnom svete

Vo svete Java ťažíme z reťazca zodpovednosti každý deň. Jedným z takýchto klasických príkladov sú Servlet filtre v Java ktoré umožňujú viacerým filtrom spracovať požiadavku HTTP. Aj keď v takom prípade každý filter vyvoláva reťazec namiesto nasledujúceho filtra.

Pozrime sa na útržok kódu uvedený nižšie, aby sme lepšie pochopili tento vzor vo filtroch servletov:

verejná trieda CustomFilter implementuje filter {public void doFilter (požiadavka ServletRequest, odpoveď ServletResponse, reťazec FilterChain) hodí IOException, ServletException {// spracuje požiadavku // odovzdá požiadavku (tj príkaz) pozdĺž reťazca filtra chain.doFilter (požiadavka, odpoveď ); }}

Ako je vidieť na útržku kódu vyššie, je potrebné ho vyvolať FilterChain‘S doFilter metóda, aby sa požiadavka postúpila ďalšiemu procesoru v reťazci.

6. Nevýhody

A teraz, keď sme videli, aký zaujímavý je reťaz zodpovednosti, nezabudnite na niektoré nevýhody:

  • Väčšinou sa môže ľahko pokaziť:
    • ak procesor nezavolá ďalší procesor, príkaz bude zrušený
    • ak procesor zavolá nesprávny procesor, môže to viesť k cyklu
  • Môže vytvárať stopy hlbokého stohu, čo môže mať vplyv na výkon
  • Môže to viesť k duplikovaniu kódu medzi procesormi a zvýšeniu údržby

7. Záver

V tomto článku sme hovorili o reťazci zodpovednosti a jeho silných a slabých stránkach pomocou reťazca na autorizáciu prichádzajúcich požiadaviek na overenie.

A ako vždy, zdrojový kód nájdete na GitHub.