Implementatie van Simple State Machines met Java Enums

1. Overzicht

In deze tutorial zullen we State Machines bekijken en bekijken hoe ze in Java kunnen worden geïmplementeerd met Enums.

We leggen ook de voordelen van deze implementatie uit in vergelijking met het gebruik van een interface en een concrete klasse voor elke staat.

2. Java-opsommingen

Een Java Enum is een speciaal type klasse dat een lijst met constanten definieert. Dit zorgt voor typeveilige implementatie en beter leesbare code.

Stel dat we een HR-softwaresysteem hebben dat verlofaanvragen van medewerkers kan goedkeuren. Dit verzoek wordt beoordeeld door de teamleider, die het escaleert naar de afdelingsmanager. De afdelingsmanager is de persoon die verantwoordelijk is voor het goedkeuren van het verzoek.

De eenvoudigste opsomming die de toestanden van een verlofaanvraag bevat, is:

openbare enum LeaveRequestState {Submitted, Escalated, Approved}

We kunnen verwijzen naar de constanten van deze opsomming:

LeaveRequestState state = LeaveRequestState.Submitted;

Enums kunnen ook methoden bevatten. We kunnen een abstracte methode in een enum schrijven, waardoor elke enum-instantie deze methode moet implementeren. Dit is erg belangrijk voor de implementatie van state machines, zoals we hieronder zullen zien.

Omdat Java-enums de class impliciet uitbreiden java.lang.Enum, kunnen ze geen andere klas uitbreiden. Ze kunnen echter een interface implementeren, net als elke andere klasse.

Hier is een voorbeeld van een enum met een abstracte methode:

public enum LeaveRequestState {Ingediend {@Override public String responsiblePerson () {retourneer "Employee"; }}, Geëscaleerd {@Override public String responsiblePerson () {return "Team Leader"; }}, Goedgekeurd {@Override public String responsiblePerson () {retourneer "Department Manager"; }}; openbare samenvatting String responsiblePerson (); }

Let op het gebruik van de puntkomma aan het einde van de laatste opsommingsconstante. De puntkomma is vereist als we een of meer methoden hebben die de constanten volgen.

In dit geval hebben we het eerste voorbeeld uitgebreid met een verantwoordelijk persoon() methode. Dit vertelt ons de persoon die verantwoordelijk is voor het uitvoeren van elke actie. Dus als we proberen de persoon te controleren die verantwoordelijk is voor het Geëscaleerd staat, het geeft ons "Teamleider":

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

Op dezelfde manier, als we controleren wie verantwoordelijk is voor het goedkeuren van het verzoek, zal het ons "Afdelingsmanager" geven:

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

3. Staatsmachines

Een toestandsmachine - ook wel een eindige toestandsmachine of eindige automaat genoemd - is een computermodel dat wordt gebruikt om een ​​abstracte machine te bouwen. Deze machines kunnen zich slechts in één toestand tegelijk bevinden. Elke staat is een status van het systeem die naar een andere staat verandert. Deze toestandsveranderingen worden overgangen genoemd.

Het kan ingewikkeld worden in de wiskunde met diagrammen en notaties, maar het is een stuk eenvoudiger voor ons programmeurs.

Het State Pattern is een van de bekende drieëntwintig ontwerppatronen van de GoF. Dit patroon ontleent het concept aan het model in de wiskunde. Het stelt een object in staat verschillende gedragingen voor hetzelfde object in te kapselen, op basis van zijn toestand. We kunnen de overgang tussen staten programmeren en later afzonderlijke staten definiëren.

Om het concept beter uit te leggen, zullen we ons voorbeeld van verlofaanvragen uitbreiden om een ​​toestandsmachine te implementeren.

4. Enums als staatsmachines

We zullen ons concentreren op de enum-implementatie van toestandsmachines in Java. Andere implementaties zijn mogelijk, en we zullen ze in de volgende sectie vergelijken.

Het belangrijkste punt van de implementatie van een statusmachine met behulp van een opsomming is dat we hebben niet te maken met het expliciet instellen van de staten. In plaats daarvan kunnen we alleen de logica geven voor de overgang van de ene staat naar de volgende. Laten we meteen naar binnen duiken:

public enum LeaveRequestState {Ingediend {@Override public LeaveRequestState nextState () {return Escalated; } @Override public String responsiblePerson () {retourneer "Medewerker"; }}, Geëscaleerd {@Override public LeaveRequestState nextState () {return Approved; } @Override public String verantwoordelijkPerson () {retourneer "Teamleider"; }}, Goedgekeurd {@Override public LeaveRequestState nextState () {retourneer dit; } @Override public String responsiblePerson () {retourneer "Department Manager"; }}; openbare samenvatting LeaveRequestState nextState (); openbare samenvatting String responsiblePerson (); }

In dit voorbeeld is de State machine-overgangen worden geïmplementeerd met behulp van de abstracte methoden van de enum. Om precies te zijn, met behulp van de volgendeState () op elke opsommingsconstante specificeren we de overgang naar de volgende staat. Indien nodig kunnen we ook een vorigeStaat () methode.

Hieronder vindt u een test om onze implementatie te controleren:

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);

We starten de verlofaanvraag in de Ingediend oorspronkelijke toestand. Vervolgens verifiëren we de toestandsovergangen met behulp van de volgendeState () methode die we hierboven hebben geïmplementeerd.

Let daar op sinds Goedgekeurd is de eindtoestand, kan er geen andere overgang plaatsvinden.

5. Voordelen van het implementeren van State Machines met Java Enums

De implementatie van toestandsmachines met interfaces en implementatieklassen kan een aanzienlijke hoeveelheid code zijn die moet worden ontwikkeld en onderhouden.

Aangezien een Java-enum in zijn eenvoudigste vorm een ​​lijst met constanten is, kunnen we een enum gebruiken om onze statussen te definiëren. En aangezien een enum ook gedrag kan bevatten, kunnen we methoden gebruiken om de overgang tussen staten te implementeren.

Het hebben van alle logica in een eenvoudige enum zorgt voor een schone en ongecompliceerde oplossing.

6. Conclusie

In dit artikel hebben we gekeken naar toestandsmachines en hoe deze met Enums in Java kunnen worden geïmplementeerd. We hebben een voorbeeld gegeven en getest.

Uiteindelijk hebben we ook de voordelen besproken van het gebruik van enums om toestandsmachines te implementeren. Als alternatief voor de interface en implementatieoplossing bieden enums een schonere en gemakkelijker te begrijpen implementatie van toestandsmachines.

Zoals altijd zijn alle codefragmenten die in dit artikel worden genoemd, te vinden in onze GitHub-repository.