Implementering av enkle tilstandsmaskiner med Java Enums

1. Oversikt

I denne opplæringen vil vi se på statsmaskiner og hvordan de kan implementeres i Java ved hjelp av Enums.

Vi forklarer også fordelene med denne implementeringen sammenlignet med å bruke et grensesnitt og en konkret klasse for hver stat.

2. Java Enums

En Java Enum er en spesiell type klasse som definerer en liste over konstanter. Dette åpner for typesikker implementering og mer lesbar kode.

La oss anta at vi har et HR-programvaresystem som kan godkjenne permisjonsforespørsler fra ansatte. Denne forespørselen blir gjennomgått av teamlederen, som eskalerer den til avdelingslederen. Avdelingsleder er den som er ansvarlig for å godkjenne forespørselen.

Det enkleste enumet som inneholder statene for en permisjonssøknad er:

offentlig enum LeaveRequestState {innsendt, eskalert, godkjent}

Vi kan referere til konstantene i dette enummet:

LeaveRequestState state = LeaveRequestState.Submitted;

Enums kan også inneholde metoder. Vi kan skrive en abstrakt metode i en enum, som vil tvinge alle enumforekomster til å implementere denne metoden. Dette er veldig viktig for implementeringen av statsmaskiner, som vi vil se nedenfor.

Siden Java enums implisitt utvider klassen java.lang.Enum, de kan ikke utvide en annen klasse. Imidlertid kan de implementere et grensesnitt, akkurat som alle andre klasser.

Her er et eksempel på en enum som inneholder en abstrakt metode:

offentlig enum LeaveRequestState {sendt inn {@ override offentlig streng ansvarlig person () {return "ansatt"; }}, Eskalert {@Override offentlig strengansvarlig person () {returner "teamleder"; }}, Godkjent {@Override public String responsiblePerson () {return "Avdelingsleder"; }}; offentlig abstrakt streng ansvarlig person (); }

Legg merke til bruken av semikolonet på slutten av den siste enumkonstanten. Semikolonet kreves når vi har en eller flere metoder som følger konstantene.

I dette tilfellet utvidet vi det første eksemplet med a ansvarlig person() metode. Dette forteller oss personen som er ansvarlig for å utføre hver handling. Så hvis vi prøver å sjekke personen som er ansvarlig for Eskalert staten, vil det gi oss "Team Leader":

LeaveRequestState state = LeaveRequestState.Escalated; assertEquals ("Team Leader", state.responsiblePerson ());

På samme måte, hvis vi sjekker hvem som er ansvarlig for å godkjenne forespørselen, vil det gi oss "Avdelingsleder":

LeaveRequestState state = LeaveRequestState.Approved; assertEquals ("Avdelingsleder", state.responsiblePerson ());

3. Statlige maskiner

En statsmaskin - også kalt en endelig statsmaskin eller endelig automat - er en beregningsmodell som brukes til å bygge en abstrakt maskin. Disse maskinene kan bare være i en tilstand på et gitt tidspunkt. Hver stat er en status for systemet som endres til en annen tilstand. Disse tilstandsendringene kalles overganger.

Det kan bli komplisert i matematikk med diagrammer og notasjoner, men ting er mye lettere for oss programmerere.

Statens mønster er et av de velkjente 23 designmønstrene til GoF. Dette mønsteret låner konseptet fra modellen i matematikk. Det tillater et objekt å kapsle inn forskjellig atferd for det samme objektet, basert på dets tilstand. Vi kan programmere overgangen mellom stater og senere definere separate stater.

For å forklare konseptet bedre vil vi utvide vårt eksempel på permisjon for å implementere en statsmaskin.

4. Enums som statsmaskiner

Vi vil fokusere på enum implementering av statsmaskiner i Java. Andre implementeringer er mulige, og vi sammenligner dem i neste avsnitt.

Hovedpoenget med statlig maskinimplementering ved hjelp av enum er at vi trenger ikke å håndtere eksplisitt innstilling av statene. I stedet kan vi bare gi logikken til hvordan du kan gå fra en tilstand til den neste. La oss dykke rett inn i:

offentlig enum LeaveRequestState {Sendt inn {@Override offentlig LeaveRequestState nextState () {retur Eskalert; } @ Override public String responsiblePerson () {return "Employee"; }}, Escalated {@Override public LeaveRequestState nextState () {return Godkjent; } @ Override public Strengansvarlig person () {returner "Team Leader"; }}, Godkjent {@Override public LeaveRequestState nextState () {returner dette; } @ Override public Strengansvarlig person () {return "Avdelingsleder"; }}; offentlig abstrakt LeaveRequestState nextState (); offentlig abstrakt streng ansvarlig person (); }

I dette eksemplet er statlige maskinoverganger implementeres ved hjelp av enums abstrakte metoder. Mer presist, ved hjelp av nextState () på hver enumkonstant spesifiserer vi overgangen til neste tilstand. Om nødvendig kan vi også implementere en previousState () metode.

Nedenfor er en test for å sjekke implementeringen vår:

LeaveRequestState state = LeaveRequestState.Submitted; state = state.nextState (); assertEquals (LeaveRequestState.Escalated, state); state = state.nextState (); assertEquals (LeaveRequestState.Approved, state); state = state.nextState (); assertEquals (LeaveRequestState.Approved, state);

Vi starter permisjonskravet i Sendt inn opprinnelige tilstand. Vi bekrefter deretter tilstandsovergangene ved å bruke nextState () metoden vi implementerte ovenfor.

Noter det siden Godkjent er den endelige tilstanden, kan ingen annen overgang skje.

5. Fordeler med å implementere statsmaskiner med Java Enums

Implementeringen av statsmaskiner med grensesnitt og implementeringsklasser kan være en betydelig mengde kode å utvikle og vedlikeholde.

Siden et Java-enum i sin enkleste form er en liste over konstanter, kan vi bruke et enum til å definere våre stater. Og siden en enum også kan inneholde atferd, kan vi bruke metoder for å gi overgangsimplementering mellom stater.

Å ha all logikken i et enkelt rom muliggjør en ren og grei løsning.

6. Konklusjon

I denne artikkelen så vi på statsmaskiner og hvordan de kan implementeres i Java ved hjelp av Enums. Vi ga et eksempel og testet det.

Etter hvert diskuterte vi også fordelene ved å bruke enums til å implementere statsmaskiner. Som et alternativ til grensesnitt- og implementeringsløsningen, gir enums en renere og lettere forståelig implementering av statsmaskiner.

Som alltid kan alle kodebitene som er nevnt i denne artikkelen finnes på GitHub-depotet vårt.