Implementering af Simple State Machines med Java Enums

1. Oversigt

I denne vejledning ser vi på statsmaskiner, og hvordan de kan implementeres i Java ved hjælp af Enums.

Vi forklarer også fordelene ved denne implementering sammenlignet med at bruge en grænseflade og en konkret klasse for hver stat.

2. Java Enums

En Java Enum er en speciel type klasse, der definerer en liste over konstanter. Dette giver mulighed for typesikker implementering og mere læselig kode.

Lad os som et eksempel antage, at vi har et HR-softwaresystem, der kan godkende orlovsanmodninger indsendt af medarbejdere. Denne anmodning gennemgås af teamlederen, som eskalerer den til afdelingslederen. Afdelingslederen er den person, der er ansvarlig for at godkende anmodningen.

Det enkleste enum, der indeholder staterne i en anmodning om orlov, er:

offentlig enum LeaveRequestState {indsendt, eskaleret, godkendt}

Vi kan henvise til konstanterne i dette enum:

LeaveRequestState state = LeaveRequestState.Submitted;

Enums kan også indeholde metoder. Vi kan skrive en abstrakt metode i en enum, som vil tvinge enhver enum-instans til at implementere denne metode. Dette er meget vigtigt for implementeringen af ​​statsmaskiner, som vi vil se nedenfor.

Da Java enums implicit udvider klassen java.lang.Enum, de kan ikke udvide en anden klasse. De kan dog implementere en grænseflade, ligesom enhver anden klasse.

Her er et eksempel på en enum, der indeholder en abstrakt metode:

offentlig enum LeaveRequestState {indsendt {@ Override offentlig streng ansvarlig person () {returner "Medarbejder"; }}, Eskaleret {@Override offentlig streng ansvarlig person () {returner "Team Leader"; }}, Godkendt {@Override offentlig streng ansvarlig person () {returner "Afdelingsleder"; }}; offentlig abstrakt streng ansvarlig person (); }

Bemærk brugen af ​​semikolon i slutningen af ​​den sidste enumkonstant. Semikolonet kræves, når vi har en eller flere metoder, der følger konstanterne.

I dette tilfælde udvidede vi det første eksempel med en ansvarlige person() metode. Dette fortæller os den person, der er ansvarlig for at udføre hver handling. Så hvis vi prøver at kontrollere den person, der er ansvarlig for Eskaleret stat, det vil give os "Team Leader":

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

På samme måde, hvis vi kontrollerer, hvem der er ansvarlig for at godkende anmodningen, vil det give os "Afdelingsleder":

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

3. Statsmaskiner

En statsmaskine - også kaldet en endelig statsmaskine eller endelig automat - er en beregningsmodel, der bruges til at bygge en abstrakt maskine. Disse maskiner kan kun være i en tilstand på et givet tidspunkt. Hver tilstand er en status for systemet, der skifter til en anden tilstand. Disse tilstandsændringer kaldes overgange.

Det kan blive kompliceret i matematik med diagrammer og notationer, men tingene er meget lettere for os programmører.

Statens mønster er et af GoFs velkendte 23 designmønstre. Dette mønster låner konceptet fra modellen i matematik. Det giver et objekt mulighed for at indkapsle forskellige opførsler for det samme objekt, baseret på dets tilstand. Vi kan programmere overgangen mellem stater og senere definere separate stater.

For at forklare konceptet bedre udvider vi vores eksempel på orlovsanmodning til implementering af en statsmaskine.

4. Enums som statsmaskiner

Vi vil fokusere på enum implementering af statsmaskiner i Java. Andre implementeringer er mulige, og vi sammenligner dem i næste afsnit.

Hovedpointen med implementering af statsmaskiner ved hjælp af enum er, at vi har ikke at gøre med eksplicit at indstille staterne. I stedet kan vi bare give logikken om, hvordan man overgår fra en tilstand til den næste. Lad os dykke lige ind i:

offentlig enum LeaveRequestState {Afsendt {@Override offentlig LeaveRequestState nextState () {return Escalated; } @ Override public String responsiblePerson () {returner "Medarbejder"; }}, Escalated {@Override public LeaveRequestState nextState () {return Godkendt; } @ Override public String responsiblePerson () {returner "Team Leader"; }}, Godkendt {@Override public LeaveRequestState nextState () {returner dette; } @ Override offentlig streng ansvarlig person () {returner "Afdelingsleder"; }}; offentlig abstrakt LeaveRequestState nextState (); offentlig abstrakt streng ansvarlig person (); }

I dette eksempel er tilstandsmaskinovergange implementeres ved hjælp af enums abstrakte metoder. Mere præcist ved hjælp af nextState () på hver enumkonstant specificerer vi overgangen til den næste tilstand. Hvis det er nødvendigt, kan vi også implementere en previousState () metode.

Nedenfor er en test for at kontrollere vores implementering:

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 orlovsanmodningen i Afsendt starttilstand. Vi verificerer derefter tilstandsovergange ved hjælp af nextState () metode, vi implementerede ovenfor.

Noter det siden godkendt er den endelige tilstand, kan ingen anden overgang ske.

5. Fordele ved at implementere statsmaskiner med Java Enums

Implementeringen af ​​statsmaskiner med grænseflader og implementeringsklasser kan være en betydelig mængde kode at udvikle og vedligeholde.

Da et Java-enum i sin enkleste form er en liste over konstanter, kan vi bruge et enum til at definere vores stater. Og da et enum også kan indeholde adfærd, kan vi bruge metoder til at give implementeringen af ​​overgangen mellem stater.

At have al logikken i et simpelt rum giver mulighed for en ren og ligetil løsning.

6. Konklusion

I denne artikel så vi på statsmaskiner og hvordan de kan implementeres i Java ved hjælp af Enums. Vi gav et eksempel og testede det.

Til sidst diskuterede vi også fordelene ved at bruge enums til at implementere statsmaskiner. Som et alternativ til grænseflade- og implementeringsløsningen giver enums en renere og lettere forståelig implementering af statsmaskiner.

Som altid kan alle kodestykker, der er nævnt i denne artikel, findes i vores GitHub-lager.