web-dev-qa-db-fra.com

Comment utiliser le modèle d'état correctement?

J'ai rencontré quelques implémentations de modèle d'état dans mon expérience de programmation et j'en ai fait quelques-unes. Je les ai vus utilisés dans divers scénarios (principalement de l'interface utilisateur et de l'analyse). Le problème est que tous sous la pression d'un développement rapide sont devenus des morceaux de code difficilement maintenables et compréhensibles. J'envisage de refactoriser l'un d'entre eux, mais j'ai du mal à trouver de bonnes ressources pour cela en ligne. Il existe de nombreux exemples simples de State Pattern en ligne, mais j'ai besoin de ressources plus détaillées. 

Donc je cherche:

  • Des exemples de pièges courants lorsque Implémentant le modèle d'état et comment. Les évitant, 
  • Exemples concrets de modèles d'état Correctement définis (comme dans certains projets/framework open source) 
  • Les expériences personnelles avec le modèle d'état Sont également les bienvenues

Merci pour votre temps

41
Ivan

@ Ivan: Il existe un certain nombre de ressources disponibles sur le Web pour Machines à états hiérarchiques (HSM). Miro Samek a beaucoup écrit sur ce modèle et propose de nombreuses informations utiles.

Quelques articles qui devraient vous intéresser:

Le principal avantage de l'utilisation de HSM par rapport aux cartes d'état FSM plates décrites par Mealy et Moore est que la hiérarchie crée une séparation des responsabilités. Les sous-états doivent uniquement gérer les conditions pour lesquelles ils ont été conçus - les événements non gérés sont transmis à l'état parent. Si l'état parent n'est pas conçu pour le gérer, il est transmis au niveau supérieur. parent et ainsi de suite. Il vous permet de créer de petites machines à états gérables qui servent toutes un seul objectif - un ordinateur pouvant tenir dans un seul objet. Au fur et à mesure que de nouvelles fonctionnalités sont ajoutées, ou que de nouvelles classes sont ajoutées, ils doivent simplement gérer leur propre petite partie du monde et transmettre les événements non gérés à leurs parents respectifs.

Une fois correctement implémenté, vous obtenez un programme robuste avec une complexité cyclomatique faible, qui est facile à modifier ou à mettre à niveau si nécessaire.

25
oosterwal

Comme vous l'avez probablement déjà lu, le modèle de conception d'état est utile lorsque l'état modifie le comportement d'un objet dont la composition inclut cet état. Cela implique l'idée d'une classe abstraite State, d'une interface ou de type énuméré _ - bien que cela dépende de la langue Duck Typing fera aussi bien - qui définit tout comportement commun et/ou les méthodes requises . 

Aspects clés

Il faut vraiment prendre en compte deux aspects clés lors de l'utilisation du modèle d'état: énumération et transition. Énumérer signifie simplement identifier l'ensemble des états possibles (par exemple, les jours de la semaine) ou, de manière plus abstraite, les types d'états (par exemple, les méta-états) tels que le début, la fin et entre les deux pour un moteur de flux de travail. entre les états où cela est généralement fait en capturant toutes les transitions possibles dans une représentation tabulaire (c'est-à-dire machine à états finis ) ou en faisant savoir à chaque état ses "transitions" possibles vers d'autres états. 

En règle générale, les transitions vont de pair avec les méta-états car il est impossible de connaître tous les états et toutes les relations à l'avance dans un système aussi dynamique où de nouveaux états, et donc des transitions, peuvent être ajoutés au moment de l'exécution. De plus, avec l'approche de la transition, certains comportements - les notifications par exemple - deviennent partie intégrante de la transition, au lieu de l'état lui-même. 

Exemples

J'ai travaillé ou discuté de plusieurs scénarios dans lesquels il s'agit d'une installation d'utilisation: 

  1. Flux de travail
  2. Adversaire du jeu d'ordinateur A.I.
  3. Processus d'orchestration 

Par workflow, je veux dire quelque chose comme jBPM . Des systèmes comme celui-ci visent à attirer l'attention, les bonnes personnes, au bon moment. Ils envoient généralement beaucoup de courriels ou un autre type de notification. De plus, le processus qu'ils représentent nécessite de pouvoir changer en même temps que l'organisation, alors que les données gérées changent généralement beaucoup plus lentement. 

Adversaire du jeu informatique A.I. est explicite. Ce n'est pas quelque chose que j'ai écrit, mais dans la conversation avec ceux qui l'ont fait, ces systèmes sont généralement autonomes. En d'autres termes, contrairement au flux de travail, le jeu ne dispose généralement pas de la possibilité de modifier le processus utilisé pour contrôler les adversaires de l'ordinateur. 

Process Orchestration est similaire au flux de travail, mais est centré sur l'intégration système, et non sur l'interaction entre personnes. Le framework Apache Mule est un exemple. Ici, state peut décrire le statut (démarré, en cours, terminé) et le type (point d'intégration ftp, point d'intégration sql). 

Conclusion

Contrairement aux autres réponses, je pense que l'encapsulation d'état est un excellent moyen de gérer les changements dans les systèmes logiciels. Bien fait, cela facilite ces modifications ou permet aux utilisateurs de le faire au moment de l'exécution. Vous faites un compromis entre plus de flexibilité et une plus grande complexité d'implémentation. Donc, une telle approche n'est probablement pas utile pour les paniers d'achat, par exemple, où le comportement est probablement très connu et ne veut pas changer. D'un autre côté, lorsque le processus est sujet à changement, il convient parfaitement. 

24
orangepips

Rien que mes 2 centimes, le modèle d'état s'avère toujours difficile à maintenir car il est difficile à comprendre par ceux qui ne l'ont pas codé. Je reviens généralement à l'ancien tableau standard de pointeurs de fonctions/méthodes, comme dans mon ancienne expérience en C. Vous venez de construire un tableau à deux dimensions de pointeurs de fonction avec état/signal pour lignes/colonnes. Plus facile à comprendre. vous avez une classe qui gère cela et vous déléguez à une autre classe pour gérer la complexité ...

my2c

8
neuro

La plupart du temps, les états d'une conception de modèle d'états traitent plusieurs états (ou sous-états de l'état), ce qui les rend plus difficiles à maintenir. 

Si un État a un type de sélection à l'intérieur, il gère principalement plus d'un État.

Je prends beaucoup de discipline pour garder les États propres.

Une solution possible consiste à créer des machines à états plus complexes (HSM) . Cela les rend beaucoup plus lisibles au niveau supérieur, car elles doivent traiter avec moins d'états.

6
Glenner003

regardez Machine à états finis . Presque toutes les langues matures ont leurs propres exemples. Comme vous n'avez pas spécifié votre langue préférée, je vais vous donner un exemple en C++: Bibliothèque Boost FSM . C'est probablement beaucoup plus compliqué que nécessaire, mais cela peut vous donner des conseils de conception à coup sûr

4
Andriy Tylychko

Donc je cherche:

  • Exemples de pièges courants lors de la mise en œuvre du modèle d'état et comment les éviter,

Le modèle d'état ne s'adapte pas bien. Imaginez une machine à états avec 10 états et 10 types de transition différents. L'ajout d'un nouvel état signifie que cet état doit définir les 10 transitions. L'ajout d'une nouvelle transition signifie que tous les 10 états doivent la définir. En bref, n'utilisez pas le modèle d'état si votre machine à états n'est pas stable et/ou si vous avez beaucoup d'états/transitions.

  • Exemples concrets de modèles d'états réalisés correctement (comme dans certains projets/framework open source)

Définissez correctement :-) L'exemple Java cité dans https://stackoverflow.com/a/2707195/1168342 concerne JSF Lifecycle, mais je pense qu'il n'y a qu'une seule transition. Aucune des autres réponses ne cite quoi que ce soit pour State. 

  • Les expériences personnelles avec le modèle d'état sont également les bienvenues

Head First Design Patterns utilise un exemple de machine Gumball pour illustrer son état. C'est ironique, mais chaque fois qu'ils prolongent la conception (ajout d'un nouvel état ou d'une transition), il y a beaucoup de code répété (en particulier pour les transitions non valides dans des états spécifiques). De plus, selon qui décide quel est le prochain état, des classes d’états individuelles peuvent être couplées les unes aux autres (dépendances entre états). Voir l'explication à la fin de cette réponse: https://stackoverflow.com/a/30424503/1168342

Le livre du GoF mentionne que les alternatives basées sur des tables ont des avantages, à savoir leur régularité. Changer les critères de transition nécessite de changer la table (et non le code).

2
Fuhrmanator

Vous devez utiliser le modèle d'état si vous avez un comportement différent pour chaque état. Peut-être devez-vous reconfigurer les transitions au moment de l'exécution. Une autre raison pour l'utiliser est que vous devrez peut-être ajouter d'autres états ultérieurement.

Imaginez un jeu de plateau comme le jeu Chinese Checkers, vous avez différents états d'interface graphique pour choisir un pion, sélectionnez un emplacement cible, etc. Dans chaque état, l'interface graphique doit se comporter différemment, certaines entrées doivent être gérées, d'autres ignorées. Il est possible d’utiliser un simple commutateur/cas, mais le modèle d’état est pratique car la logique est encapsulée, le code associé est également différent. Cela facilite l’introduction de nouveaux états sans affecter la plupart/tous les autres états (en fonction de la personne qui est responsable de la définition des transitions: soit l’état connaît ses transitions sortantes, soit elles pourraient être définies à l’exécution, par exemple à l’aide du constructeur).

Comme vous pouvez le voir dans cet exemple , GuiController utilise une interface IGuiState pour modifier son comportement à la demande. Une implémentation peut être vue ici .

Le principal écueil est d'utiliser switch/case lorsque vous devez faire preuve de souplesse. Étant donné que l'indirection prend un peu plus de temps, je le recommanderais pour un nombre fixe d'états assez simples. Si vous devez implémenter un protocole réseau de bas niveau assez rapide, généralement trop onéreux.

1
mbx

Je construis un évaluateur d'expression qui a la capacité d'évaluer des ensembles d'éléments. J'ai trouvé le modèle d'état très utile pour distinguer ce qui peut ou ne peut pas être fait pour un ensemble en fonction de son état. c'est à dire: ouvert, fermé, inactif, actif ect. Les FSM sont très faciles à dessiner et réduisent la complexité du code en supprimant le besoin de grands blocs d'instructions ifelse pour définir ce que doit faire la fonctionnalité en fonction de ses attributs inclus. Cela rend ces conditions plus explicites en les transformant en classes. C'est l'un de mes modèles préférés jusqu'à présent.

0
user5484291