Uzorak dizajna lanca odgovornosti na Javi
1. Uvod
U ovom ćemo članku pogledati široko korištene obrazac dizajna ponašanja: Lanac odgovornosti.
U našem prethodnom članku možemo pronaći više obrazaca dizajna.
2. Lanac odgovornosti
Wikipedia definira Lanac odgovornosti kao obrazac dizajna koji se sastoji od "izvora naredbenih objekata i niza obrađenih objekata".
Svaki objekt obrade u lancu odgovoran je za određenu vrstu naredbe i obrada je gotova, prosljeđuje naredbu sljedećem procesoru u lancu.
Lanac odgovornosti obrazac je zgodan za:
- Odvajanje pošiljatelja i primatelja naredbe
- Odabir strategije obrade u vrijeme obrade
Pa, pogledajmo jednostavan primjer uzorka.
3. Primjer
Koristit ćemo Lanac odgovornosti za stvaranje lanca za rukovanje zahtjevima za provjeru autentičnosti.
Dakle, pružatelj ulazne provjere autentičnosti bit će naredba, a svaki procesor za provjeru autentičnosti bit će zaseban procesor objekt.
Napravimo prvo apstraktnu osnovnu klasu za naše procesore:
javna apstraktna klasa AuthenticationProcessor {public AuthenticationProcessor nextProcessor; // standardni sažetak konstruktora boolean isAuthorized (AuthenticationProvider authProvider); }
Dalje, kreirajmo konkretne procesore koji se šire Procesor autentifikacije:
javna klasa OAuthProcessor proširuje AuthenticationProcessor {javni OAuthProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override javni logički isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof OAuthTokenProvider) {return true; } else if (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } return false; }}
javna klasa UsernamePasswordProcessor proširuje AuthenticationProcessor {public UsernamePasswordProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override javni boolean isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof UsernamePasswordProvider) {return true; } else if (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } return false; }}
Ovdje smo stvorili dva konkretna procesora za naše dolazne zahtjeve za autorizacijom: UsernamePasswordProcessor i OAuthProcessor.
Za svaku smo nadjačali isAuthorized metoda.
Izradimo sada nekoliko testova:
javna klasa ChainOfResponsibilityTest {privatni statički AuthenticationProcessor getChainOfAuthProcessor () {AuthenticationProcessor oAuthProcessor = novi OAuthProcessor (null); vratiti novi UsernamePasswordProcessor (oAuthProcessor); } @Test javna praznina givenOAuthProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertTrue (authProcessorChain.isAuthorized (novi OAuthTokenProvider ())); } @Test javna praznina givenSamlProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertFalse (authProcessorChain.isAuthorized (novi SamlTokenProvider ())); }}
Gornji primjer stvara lanac procesora za provjeru autentičnosti: UsernamePasswordProcessor -> OAuthProcessor. U prvom testu autorizacija uspije, a u drugom ne uspije.
Prvi, UsernamePasswordProcessor provjerava je li pružatelj autentifikacije instanca UsernamePasswordProvider.
Nije očekivani unos, UsernamePasswordProcessor delegati u OAuthProcessor.
Posljednji, OAuthProcessor obrađuje naredbu. U prvom se testu podudara i test prolazi. U drugom, u lancu više nema procesora i, kao rezultat, test ne uspijeva.
4. Principi provedbe
Moramo imati na umu nekoliko važnih principa tijekom provođenja lanca odgovornosti:
- Svaki procesor u lancu imat će svoju implementaciju za obradu naredbe
- U našem primjeru iznad, svi procesori imaju svoju implementaciju isAuthorized
- Svaki procesor u lancu trebao bi imati referencu na sljedeći procesor
- Iznad, UsernamePasswordProcessor delegati u OAuthProcessor
- Svaki procesor odgovoran je za delegiranje sljedećem procesoru, pazite da ispustite naredbe
- Opet u našem primjeru, ako je naredba instanca SamlProvider tada se zahtjev možda neće obraditi i bit će neovlašten
- Procesori ne bi trebali stvarati rekurzivni ciklus
- U našem primjeru nemamo ciklus u našem lancu: UsernamePasswordProcessor -> OAuthProcessor. Ali, ako izričito postavimo UsernamePasswordProcessor kao sljedeći procesor OAuthProcessor, tada završimo s ciklusom u našem lancu: UsernamePasswordProcessor -> OAuthProcessor -> UsernamePasswordProcessor. Uzimanje sljedećeg procesora u konstruktoru može vam u tome pomoći
- Samo jedan procesor u lancu obrađuje zadanu naredbu
- U našem primjeru, ako dolazna naredba sadrži instancu OAuthTokenProvider, tada samo OAuthProcessor će se nositi s naredbom
5. Korištenje u stvarnom svijetu
U svijetu Jave svakodnevno koristimo Lanac odgovornosti. Jedan od takvih klasičnih primjera su Servlet Filteri u Java koji omogućuju više filtara za obradu HTTP zahtjeva. Iako u tom slučaju, svaki filtar poziva lanac umjesto sljedećeg filtra.
Pogledajmo dolje isječak koda za bolje razumijevanje ovog uzorka u filtrima servleta:
javna klasa CustomFilter implementira Filter {public void doFilter (ServletRequest zahtjev, ServletResponse odgovor, FilterChain lanac) baca IOException, ServletException {// obrađuje zahtjev // prosljeđuje zahtjev (tj. naredbu) duž lanca lanca filtra.doFilter (zahtjev, odgovor ); }}
Kao što se vidi u isječku koda gore, moramo se pozvati FilterChain‘S doFilter metodu kako bi se zahtjev proslijedio sljedećem procesoru u lancu.
6. Mane
A sada kad smo vidjeli koliko je lanac odgovornosti zanimljiv, imajmo na umu neke nedostatke:
- Uglavnom se lako može slomiti:
- ako procesor ne uspije pozvati sljedeći procesor, naredba će pasti
- ako procesor pozove pogrešni procesor, to može dovesti do ciklusa
- Može stvoriti duboke tragove stoga, što može utjecati na performanse
- To može dovesti do dupliciranja koda u procesorima, povećavajući održavanje
7. Zaključak
U ovom smo članku govorili o lancu odgovornosti i njegovim prednostima i slabostima uz pomoć lanca za autorizaciju dolaznih zahtjeva za provjeru autentičnosti.
Kao i uvijek, izvorni kod možete pronaći na GitHubu.