13

Update:

State pattern might a wrong way to solve this. Hence, any other pattern is welcome. Basically I'm looking for a way to have guard conditions for each state yet having a clean and maintainable code. How would front-end side routing systems like, emberjs, ui-router and react-router implement guard conditions to avoid entering a specific state if the condition is not met?


I want to implement a finite state machine by using State Pattern but I can't wrap my head around it. In short it's like:

If error -> error state
If A && B && C -> second state
If only A -> first state

At any state, on error, we go to error state. inputs (events) A, B and C might arrive at any order but if they all pass we go to 2nd state. If only input A applies, then we go to 1st state.

The following state diagram is taken from Martin Fowler's Domain Specific Language book.

DSL

In the description he says:

Miss Grant, has a secret compartment in her bedroom that is normally locked and concealed. To open it, she has to close the door, then open the second drawer in her chest and turn her bedside light on in either order. Once these are done, the secret panel is unlocked for her to open.

I emphasize, that turning light and opening 2nd drawer can happen in either order. Same as A, B and C.

Based on @SQLPolice comment and the book, I have drawn this:

enter image description here

But the problem is, I might have (A && B && C && D && D && E). In that case it's gonna be cumbersome to have all of the combination interim states.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
Sam R.
  • 16,027
  • 12
  • 69
  • 122
  • you have a start state, I assume ? – SQL Police Jul 01 '15 at 08:14
  • What are you drawing this in... UML/Flow...? – David Barker Jul 01 '15 at 08:16
  • @DavidBarker, neither. I just need something visual to understand how to implement. – Sam R. Jul 01 '15 at 08:30
  • OK, but when you have **A only**, then you want to go to a different state. But what happens if you have A as first event ? How do you know that B or C will follow? – SQL Police Jul 01 '15 at 08:46
  • Oh, that's a nice drawing now! - Yes, you are right, it get's very very cumbersome when getting more complex. That's why you use tools to create such state machines - for example `lex`, `flex`, etc. (for lexical analysis). They create C code with a lot of labels and `goto` jumps ... – SQL Police Jul 01 '15 at 11:33

3 Answers3

4

You can use some form of lexical analysis for this. I would approach this by limiting the ability to transition from a state unless the constraints placed on the edge between the two states are met. I wrote an FSM in PHP recently for the Laravel framework that has an example such as this where various constraints are all required to be true before a transition can occur. It uses pseudo states or handles within a state to toggle a flag stating that a process has completed. Only when all flags are set to true can the state transition.

Sample lexical state analysis

Using the FSM package I wrote for laravel, an example FSM setup would look something like this.

Each state would (either onEnter) or via a pseudo state set it's constraint flag on the FSM OR State to true.

This would also trigger a checkReady() that would trigger the transition or keep the current state based on the constraint flags.

Adding in new constraints is a case of adding them to an array of constraints within the state or the containing FSM and building a method to allow the constraint to be removed when a task is performed.

When you are looking at multiple states, with each state forming a requirement on the constraints. A sample state would look something like this.

When you are looking at a single state with pseudo states / handlers. The state would look something like this, where it's logic is contained.

David Barker
  • 14,484
  • 3
  • 48
  • 77
3

A quick draft looks like this:

enter image description here

SQL Police
  • 4,127
  • 1
  • 25
  • 54
  • Thanks, but how would I avoid writing `if (A && B && C)`? The reason is, I already have a lot of if and else with various conditions. The only reason to pick state machine was to avoid doing that. – Sam R. Jul 01 '15 at 08:28
  • Ah, I see. What's behind that - is that a homework for school, or what do you want to realize ? – SQL Police Jul 01 '15 at 08:34
  • It's not a homework. I'm older than this kinda thing. It's a real problem we have and we are trying to simplify things. – Sam R. Jul 01 '15 at 08:36
  • It's a while ago, but I can roughly remember how this was done with lexical analysis. You can dissolve the "A & B & C" by using a sequence of *interim states*, like this: If you have A, then switch to interim state 1. Now, there, if you have B, then go to Interim State 2, but if not, then go to your Final State 1. In Interim State 1, if you have C, then go to Final State 2. This is one possible way like automated tools would do it. – SQL Police Jul 01 '15 at 08:42
  • Make a transition event `D` where `D = (A && B && C)`? – Fuhrmanator Jul 02 '15 at 15:36
1

A state machine abstraction is comprised of:

  1. States
  2. Events or inputs
  3. Transitions
  4. Actions

A statement like a&&b&&c is effectively an event or input... a label for a transition. So it needs to be mapped to an event if you're going to fit into the state machine abstraction. You need to write code to do that mapping.

If your state machine is generally driven by conditions like these you need to hook events where a b and c change, or check them periodically on timer. Any time they change, your code maps to an event and posts them into whatever code advances the state machine.