Kæde af ansvarsdesignmønster i Java

1. Introduktion

I denne artikel vil vi se på et meget brugt adfærdsmæssige mønster: Ansvarlighedskæde.

Vi kan finde flere designmønstre i vores tidligere artikel.

2. Kæde af ansvar

Wikipedia definerer Chain of Responsibility som et designmønster bestående af "en kilde til kommandoobjekter og en række behandlingsobjekter".

Hvert behandlingsobjekt i kæden er ansvarlig for en bestemt type kommando, og behandlingen udføres, det videresender kommandoen til den næste processor i kæden.

Mønsteret Chain of Responsibility er praktisk til:

  • Afkobling af en afsender og modtager af en kommando
  • Valg af en behandlingsstrategi på behandlingstidspunktet

Så lad os se et simpelt eksempel på mønsteret.

3. Eksempel

Vi skal bruge Chain of Responsibility til at oprette en kæde til håndtering af godkendelsesanmodninger.

Så leverandøren af ​​inputgodkendelse vil være kommando, og hver godkendelsesprocessor vil være en separat processor objekt.

Lad os først oprette en abstrakt basisklasse til vores processorer:

offentlig abstrakt klasse AuthenticationProcessor {public AuthenticationProcessor nextProcessor; // standardkonstruktører offentlig abstrakt boolsk erAuthorized (AuthenticationProvider authProvider); }

Lad os derefter oprette konkrete processorer, der strækker sig AuthenticationProcessor:

offentlig klasse OAuthProcessor udvider AuthenticationProcessor {public OAuthProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override public boolean isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof OAuthTokenProvider) {return true; } ellers hvis (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } returner falsk; }}
offentlig klasse UsernamePasswordProcessor udvider AuthenticationProcessor {public UsernamePasswordProcessor (AuthenticationProcessor nextProcessor) {super (nextProcessor); } @Override public boolean isAuthorized (AuthenticationProvider authProvider) {if (authProvider instanceof UsernamePasswordProvider) {return true; } ellers hvis (nextProcessor! = null) {return nextProcessor.isAuthorized (authProvider); } returner falsk; }}

Her oprettede vi to konkrete processorer til vores indgående godkendelsesanmodninger: BrugernavnPasswordProcessor og OAuthProcessor.

For hver enkelt overstyrer vi er autoriseret metode.

Lad os nu oprette et par tests:

offentlig klasse ChainOfResponsibilityTest {privat statisk AuthenticationProcessor getChainOfAuthProcessor () {AuthenticationProcessor oAuthProcessor = ny OAuthProcessor (null); returner nyt brugernavnPasswordProcessor (oAuthProcessor); } @ Test offentlig ugyldighed givetOAuthProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertTrue (authProcessorChain.isAuthorized (ny OAuthTokenProvider ())); } @Test offentlig ugyldighed givenSamlProvider_whenCheckingAuthorized_thenSuccess () {AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor (); assertFalse (authProcessorChain.isAuthorized (ny SamlTokenProvider ())); }}

Eksemplet ovenfor opretter en kæde af godkendelsesprocessorer: UsernamePasswordProcessor -> OAuthProcessor. I den første test lykkes godkendelsen, og i den anden mislykkes den.

Først, BrugernavnPasswordProcessor kontrollerer, om godkendelsesudbyderen er en forekomst af BrugernavnPasswordProvider.

Ikke det forventede input, BrugernavnPasswordProcessor delegerede til OAuthProcessor.

Sidst, den OAuthProcessor behandler kommandoen. I den første test er der en kamp, ​​og testen består. I det andet er der ikke flere processorer i kæden, og resultatet mislykkes derfor.

4. Implementeringsprincipper

Vi er nødt til at holde nogle få vigtige principper i tankerne, når vi implementerer Chain of Responsibility:

  • Hver processor i kæden har sin implementering til behandling af en kommando
    • I vores eksempel ovenfor har alle processorer deres implementering af er autoriseret
  • Hver processor i kæden skal have henvisning til den næste processor
    • Over, BrugernavnPasswordProcessor delegerede til OAuthProcessor
  • Hver processor er ansvarlig for at delegere til den næste processor, så pas på tabte kommandoer
    • Igen i vores eksempel, hvis kommandoen er en forekomst af SamlProvider derefter behandles anmodningen muligvis ikke og vil være uautoriseret
  • Processorer bør ikke danne en rekursiv cyklus
    • I vores eksempel har vi ikke en cyklus i vores kæde: UsernamePasswordProcessor -> OAuthProcessor. Men hvis vi udtrykkeligt indstiller BrugernavnPasswordProcessor som næste processor af OAuthProcessor, så ender vi med en cyklus i vores kæde: UsernamePasswordProcessor -> OAuthProcessor -> UsernamePasswordProcessor. At tage den næste processor i konstruktøren kan hjælpe med dette
  • Kun en processor i kæden håndterer en given kommando
    • I vores eksempel, hvis en indkommende kommando indeholder en forekomst af OAuthTokenProvider, så kun OAuthProcessor vil håndtere kommandoen

5. Anvendelse i den virkelige verden

I Java-verdenen drager vi fordel af Chain of Responsibility hver dag. Et sådant klassisk eksempel er Servlet-filtre i Java der tillader flere filtre at behandle en HTTP-anmodning. Skønt i så fald hvert filter påberåber kæden i stedet for det næste filter.

Lad os se på nedenstående kodestykke for bedre forståelse af dette mønster i Servlet-filtre:

offentlig klasse CustomFilter implementerer Filter {public void doFilter (ServletRequest anmodning, ServletResponse svar, FilterChain kæde) kaster IOException, ServletException {// behandler anmodningen // videresender anmodningen (dvs. kommandoen) langs filterkæden. doFilter (anmodning, svar ); }}

Som det ses i kodestykket ovenfor, skal vi påberåbe os Filterkæde'S doFilter metode for at videresende anmodningen til næste processor i kæden.

6. Ulemper

Og nu hvor vi har set, hvor interessant Chain of Responsibility er, lad os huske nogle ulemper:

  • For det meste kan det let gå i stykker:
    • hvis en processor ikke ringer til den næste processor, slettes kommandoen
    • hvis en processor kalder den forkerte processor, kan det føre til en cyklus
  • Det kan skabe dybe stakspor, som kan påvirke ydeevnen
  • Det kan føre til duplikatkode på tværs af processorer, hvilket øger vedligeholdelsen

7. Konklusion

I denne artikel talte vi om Chain of Responsibility og dets styrker og svagheder ved hjælp af en kæde til at godkende indgående godkendelsesanmodninger.

Og som altid kan kildekoden findes på GitHub.