Implémentation de machines à états simples avec des énumérations Java

1. Vue d'ensemble

Dans ce didacticiel, nous examinerons les machines d'état et comment elles peuvent être implémentées en Java à l'aide d'Enums.

Nous expliquerons également les avantages de cette implémentation par rapport à l'utilisation d'une interface et d'une classe concrète pour chaque état.

2. Énumérations Java

Un Java Enum est un type spécial de classe qui définit une liste de constantes. Cela permet une implémentation de type sécurisé et un code plus lisible .

À titre d'exemple, supposons que nous ayons un système logiciel RH capable d'approuver les demandes de congé soumises par les employés. Cette demande est examinée par le chef d'équipe, qui la transmet au chef de service. Le chef de service est la personne chargée d'approuver la demande.

L'énumération la plus simple qui contient les états d'une demande de congé est:

public enum LeaveRequestState { Submitted, Escalated, Approved }

Nous pouvons nous référer aux constantes de cette énumération:

LeaveRequestState state = LeaveRequestState.Submitted;

Les énumérations peuvent également contenir des méthodes. Nous pouvons écrire une méthode abstraite dans un enum, ce qui forcera chaque instance enum à implémenter cette méthode. Ceci est très important pour l'implémentation des machines d'état, comme nous le verrons ci-dessous.

Puisque les énumérations Java étendent implicitement la classe java.lang.Enum , elles ne peuvent pas étendre une autre classe. Cependant, ils peuvent implémenter une interface, comme n'importe quelle autre classe.

Voici un exemple d'énumération contenant une méthode abstraite:

public enum LeaveRequestState { Submitted { @Override public String responsiblePerson() { return "Employee"; } }, Escalated { @Override public String responsiblePerson() { return "Team Leader"; } }, Approved { @Override public String responsiblePerson() { return "Department Manager"; } }; public abstract String responsiblePerson(); }

Notez l'utilisation du point-virgule à la fin de la dernière constante d'énumération. Le point-virgule est obligatoire lorsque nous avons une ou plusieurs méthodes suivant les constantes.

Dans ce cas, nous avons étendu le premier exemple avec une méthode responsablePerson () . Cela nous indique la personne responsable de l'exécution de chaque action. Donc, si nous essayons de vérifier la personne responsable de l' état Escaladé , cela nous donnera «Team Leader»:

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

De la même manière, si nous vérifions qui est responsable de l'approbation de la demande, il nous donnera «Responsable de département»:

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

3. Machines d'état

Une machine à états - également appelée machine à états finis ou automate fini - est un modèle de calcul utilisé pour construire une machine abstraite. Ces machines ne peuvent être que dans un seul état à la fois. Chaque état est un état du système qui passe à un autre état. Ces changements d'état sont appelés transitions.

Cela peut devenir compliqué en mathématiques avec des diagrammes et des notations, mais les choses sont beaucoup plus faciles pour nous, programmeurs.

Le modèle d'état est l'un des vingt-trois modèles de conception bien connus du GoF. Ce modèle emprunte le concept au modèle en mathématiques. Il permet à un objet d'encapsuler différents comportements pour le même objet, en fonction de son état. Nous pouvons programmer la transition entre les états et définir plus tard des états séparés.

Pour mieux expliquer le concept, nous allons développer notre exemple de demande de congé pour implémenter une machine à états.

4. Enums en tant que machines d'état

Nous allons nous concentrer sur l'implémentation enum des machines d'état en Java. D'autres implémentations sont possibles, et nous les comparerons dans la section suivante.

Le point principal de l'implémentation de la machine d'état utilisant une énumération est que nous n'avons pas à nous occuper de définir explicitement les états . Au lieu de cela, nous pouvons simplement fournir la logique sur la façon de passer d'un état à un autre. Plongeons-nous dans:

public enum LeaveRequestState { Submitted { @Override public LeaveRequestState nextState() { return Escalated; } @Override public String responsiblePerson() { return "Employee"; } }, Escalated { @Override public LeaveRequestState nextState() { return Approved; } @Override public String responsiblePerson() { return "Team Leader"; } }, Approved { @Override public LeaveRequestState nextState() { return this; } @Override public String responsiblePerson() { return "Department Manager"; } }; public abstract LeaveRequestState nextState(); public abstract String responsiblePerson(); }

Dans cet exemple, les transitions de la machine d'état sont implémentées à l'aide des méthodes abstraites de l'énumération . Plus précisément, en utilisant nextState () sur chaque constante d'énumération, nous spécifions la transition vers l'état suivant. Si nécessaire, nous pouvons également implémenter une méthode previousState () .

Voici un test pour vérifier notre implémentation:

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

Nous commençons la demande de congé dans l' état initial Soumis . Nous vérifions ensuite les transitions d'état en utilisant la méthode nextState () que nous avons implémentée ci-dessus.

Notez que puisque Approuvé est l'état final, aucune autre transition ne peut se produire .

5. Avantages de l'implémentation de machines d'état avec des énumérations Java

L'implémentation de machines d'état avec des interfaces et des classes d'implémentation peut représenter une quantité importante de code à développer et à maintenir.

Comme une énumération Java est, dans sa forme la plus simple, une liste de constantes, nous pouvons utiliser une énumération pour définir nos états. Et comme une énumération peut également contenir un comportement, nous pouvons utiliser des méthodes pour fournir l'implémentation de la transition entre les états.

Avoir toute la logique dans une simple énumération permet une solution propre et simple.

6. Conclusion

Dans cet article, nous avons examiné les machines à états et comment elles peuvent être implémentées en Java à l'aide d'Enums. Nous avons donné un exemple et l'avons testé.

Finalement, nous avons également discuté des avantages de l'utilisation d'énumérations pour implémenter des machines à états. En tant qu'alternative à l'interface et à la solution d'implémentation, les énumérations fournissent une implémentation plus claire et plus facile à comprendre des machines d'état.

Comme toujours, tous les extraits de code mentionnés dans cet article se trouvent dans notre référentiel GitHub.