This week's book giveaway is in the Mac OS forum. We're giving away four copies of a choice of "Take Control of Upgrading to Yosemite" or "Take Control of Automating Your Mac" and have Joe Kissell on-line! See this thread for details.
Following on from an earlier post I'm trying to design a state machine and wondered if anyone with more experience of these could give me their opinion on this situation.
I'm using a table driven approach where I have rows holding the following
Current State, Event, Condition, Transition, Next State
Where each one of these is a Class
Current State = where you are now. Event = What happened, plus potential input data Condition = What must be satisfied for transition to occur. Transition = Stuff that will happen on the transition Next state = What the next �current� state is.
I have a situation where I may need to display a list of "Diagnostic" candidates.
a)If Diagnostic candidates are available display the diagnostic candidate screen.
b)If Diagnostic candidates aren�t available go to another screen
Effectively the next state is dependent on a non-trivial excercise.
I could use
Event 1 Condition1= Are diagnostic candidates, Do Stuff, Diagnostic state Event 1 Condition2= Aren�t diagnostic candidates, Do Stuff, Another state
To determine if there are diagnostic candidates is a fairly time consuming process, this set up will cause the Condition1 and 2 to execute the same code.
Would it be better to have an Event like this Event1, null, Check if candidates and issue appropriate event, null.
EventWithCandidates,null,do stuff, Diagnostic screen state
EventWithoutCandidates,null, do stuff, Another screen state.
The one thing that worries me about this is that the top entry has no "next state", and I would have to accommodate for this in the state machine code, also the Transition object would be issuing an Event, rather than the client.
Another way would be for Condition1 to set up the candidate list somewhere and Condition2 be coded to look for this, but this introduces a sequential dependency between conditions.
Or I could condition the Transition and State logic on the condition output but that seems naff.
How is this usually done, is there a better way?
[ November 07, 2005: Message edited by: Graham VMead ] [ November 07, 2005: Message edited by: Graham VMead ]
Joined: Sep 22, 2003
Just had a thought, should really get the candidate list in the Event, that would do it.
I think I've always managed to get the conditions you mention into the current state or into the event. With or without diagnostics could be the current state ...
I don't know if that makes sense in your world. This can lead you into having many states in excruciating detail. See if the following links (from a school project that generates database data) make sense. The diagram is an RTN format description of a subset of DDL syntax. The spreadsheet matches this and drives the program. When an event occurs (a parser token is found) it sends the "message" to the processing engine which invokes a command and goes to the next state.
Most non-trivial state-based systems encounter problems like this. From your description it seems that all your "states" are probably associated with something visible (such as a user input screen). I have usually handled this using the introduction of "invisible" or "navigation" states.
The job of an invisible state is to perform complex processing that doesn't belong to any particular visible state, but that helps the system decide which visible state to show next.
So from the users' piont of view it steps directly from one screen to another, but from the point of view of there is another intermediate state whose job is solely to decide which visible state follows.
The step of moving the "next state" calculation out of the state itself into an external state specification is a vital one, but the step of separating processing from the visible states into invisible states is just as important for a rpobust application.
FROM STATE EVENT TO STATE SCREEN A "next button" INVIS 1 INVIS 1 "has diagnostics" SCREEN B INVIS 1 "no diagnostics" SCREEN C SCREEN B ... SCREEN C ... SCREEN X "continue" SCREEN Y
In your example am I right in assuming the INVIS 1 state is responsible for the processing to find if there are candidates?
The application is based around screen navigation (with a few other bits and bobs).
One last question, using your example a normal transtion could be
Assume current state is SCREEN X
Event myEvent = new Event("continue"); State nextState = stateMachine.next(myEvent);
Using the invis way
Assume current state is SCREEN A
Event myEvent = new Event("next button"); State nextState = stateMachine.next(myEvent);
what mechanism do you use so that internally the stateMachine knows this is a 2 stage process
get the continue Event,
resolve it to the invis1 state,
find the candidates, (does the Invis 1 state object do this?)
Issue "nocandidates"/"candidates" event (Does invis 1 state issue next on statemachine or is statemachine coded to recognise this as intermediate state?)
Joined: Jan 07, 1999
what mechanism do you use so that internally the stateMachine knows this is a 2 stage process?
It shouldn't care. Every transition is still just a single step. The invisible state simply raises one of its exit events when it has made its decision just like the screens do when a user presses a button or whatever.
I have written systems which have many more "invisible" states than visible ones. Sometimes there might be a chain of several invisible states before another visible state appears which requires a decision from a user.
Joined: Sep 22, 2003
sorry to be dense
The example I'm looking at goes to the next state by issuing a next method on the statemachine passing in an Event
Are you saying that in this case the invis1 state would
a) Find whether there are candidates b) Issue next() method on state machine passing in appropriate Event type
Joined: Jan 07, 1999
When the code in the invisible state (which works out if there are any diagnostic candidates) gets an answer, then the state should change. So it gives the state machine some sort of "I have diagnostic candidates" or "I do not have diagnostic candidates" event. The state machine uses this event to decide which state object (visible or invisible) to call next.
It might help to think of visible states showing something them waiting for user input, while invisible states set up some processing and wait for a result. Then end result of both is the same - an event of some sort is passed to the state machine so it can work out what to do next.
Joined: Sep 22, 2003
Thanks a lot for your help. If its not a real pain, have you got any tips on the following,
Say I've got a screen (HTML) with 3 tabs e.g Summary, Diagnostics, Log.
Each tab has the concept of internal states, so Diagnostics has sub states e.g "Show diagnostic candidates" "process candidate" etc. The user has the ability to jump from say "Show Diagnostic candidates" in the "Diagnostic" pane to "Summary". On returning to the "Diagnostic" pane the system must remember the "Diagnostic" sub state and show the appropiate screen.
From trawling the net this seems to be "Orthogonal" states, but I have yet to find an implementation example.
Would this be implemented with a top level State machine class holding a list of Child "State machines".
The Top level state machine would know which current state it was in "Summary" "Diagnostic" "Log" etc.
When the top level SM received an Event how would it know which Child SM to route to. I've seen an example where it routes the event to all child SM's in turn?!
How would it distinguish between an event that changed the top level current state e.g going from diagnostics to summary, and one that was a change in a childs state, e.g diagnostic screen 1 to screen 2.
May be I'm on the wrong track.
Joined: Jan 07, 1999
If I read you right this sounds like another common state machine problem. Am I right in rephrasing it as:
You want to bne able to use the same state behaviour, but with a different set of destination states depending on what you have done in the program.
If that's the case, i'd personally steer clear of "sub state machines" or "internal states" and try very hard to keep it all at one level.
Remember that when you have "invisible states" there is nothing tying you to the idea that one screen always equals one state. It's perfectly reasonable to also have state transitions that take place while one screen is on display. One visible screen could easily correspond to two or more states ("diagnostoc with candidates", "diagnostic with summary", etc.)