Created
September 25, 2011 08:43
-
-
Save neilmanuell/1240398 to your computer and use it in GitHub Desktop.
declaration of fluent Latchable Door FSM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LATCH | |
// NB: if this Process is called in a State not declared as initiating a process, | |
// or as throwing an error, nothing will happen, but silently | |
// The CommandFlowMap will verify that each transition is valid, and all States have been declared. | |
commandFlowMap.configureProcess() | |
.onEvent( ProcessEventTypes.LATCH, ProcessEvent ) | |
.ifCurrentState( StateNames.LOCKED ) | |
.thenTransitionTo( StateNames.CLOSED, StateNames.OPENED, StateNames.LATCHED ) | |
.ifCurrentState( StateNames.CLOSED ) | |
.thenTransitionTo( StateNames.OPENED, StateNames.LATCHED ) | |
.ifCurrentState( StateNames.OPENED ) | |
.thenTransitionTo( StateNames.LATCHED ) | |
.ifCurrentState( StateNames.LATCHED ) | |
.thenThrowError(); | |
// OPEN | |
commandFlowMap.configureProcess() | |
.onEvent( ProcessEventTypes.OPEN, ProcessEvent ) | |
.ifCurrentState( StateNames.LOCKED ) | |
.thenTransitionTo( StateNames.CLOSED, StateNames.OPENED ) | |
.ifCurrentState( StateNames.CLOSED, StateNames.LATCHED ) | |
.thenTransitionTo( StateNames.OPENED ) | |
.ifCurrentState( StateNames.OPENED ) | |
.thenThrowError(); | |
// CLOSE | |
commandFlowMap.configureProcess() | |
.onEvent( ProcessEventTypes.CLOSE, ProcessEvent ) | |
.ifCurrentState( StateNames.LOCKED, StateNames.OPENED ) | |
.thenTransitionTo( StateNames.CLOSED ) | |
.ifCurrentState( StateNames.LATCHED ) | |
.thenTransitionTo( StateNames.OPENED, StateNames.CLOSED ) | |
.ifCurrentState( StateNames.CLOSED ) | |
.thenThrowError(); | |
//LOCK | |
commandFlowMap.configureProcess() | |
.onEvent( ProcessEventTypes.LOCK, ProcessEvent ) | |
.ifCurrentState( StateNames.CLOSED ) | |
.thenTransitionTo( StateNames.LOCKED ) | |
.ifCurrentState( StateNames.OPENED ) | |
.thenTransitionTo( StateNames.CLOSED, StateNames.LOCKED ) | |
.ifCurrentState( StateNames.LATCHED ) | |
.thenTransitionTo( StateNames.OPENED, StateNames.CLOSED, StateNames.LOCKED ) | |
.ifCurrentState( StateNames.LOCKED ) | |
.thenThrowError(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commandFlowMap | |
.configureState( StateNames.LOCKED ) | |
.setEnteringGuards( OnlyIfKeyFitsLock ) | |
.setExitingGuards( OnlyIfKeyFitsLock ) | |
.addTransitionTargets( StateNames.CLOSED ); | |
commandFlowMap | |
.configureState( StateNames.CLOSED ) | |
.addTransitionTargets( StateNames.LOCKED, StateName.OPEN ); | |
commandFlowMap | |
.configureState( StateNames.OPENED ) | |
.addTransitionTargets( StateNames.CLOSED, StateName.LATCHED ); | |
commandFlowMap | |
.configureState( StateNames.LATCHED ) | |
.addTransitionTargets( StateNames.OPENED ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LOCKED | |
commandFlowMap | |
.map.asCommandClass( EngageLockCmd ) | |
.toState( StateNames.LOCKED ) | |
.duringEnteredPhase(); | |
commandFlowMap | |
.map.asCommandClass( DisengageLockCmd ) | |
.toState( StateNames.LOCKED ) | |
.duringTearDownPhase(); | |
commandFlowMap | |
.map.asCommandClass( HandleIncorrectKeyMacroCmd ) | |
.toState( StateNames.LOCKED ) | |
.duringCancelledPhase(); | |
// CLOSED | |
commandFlowMap | |
.map.asCommandClass( PushDoorToCmd ) | |
.withGuards( OnlyIfDoorAjar ) | |
.toState( StateNames.CLOSED ) | |
.duringEnteredPhase(); | |
// OPENED | |
commandFlowMap | |
.map.asCommandClass( PullDoorAjarCmd ) | |
.withGuards( OnlyIfDoorPulledTo ) | |
.toState( StateNames.OPENED ) | |
.duringEnteredPhase(); | |
// LATCHED | |
commandFlowMap | |
.map.asCommandClass( EngageLatchCmd ) | |
.toState( StateNames.LATCHED ) | |
.duringEnteredPhase(); | |
commandFlowMap | |
.map.asCommandClass( DisengageLatchCmd ) | |
.toState( StateNames.LATCHED ) | |
.duringTearDownPhase(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Inject] | |
public var eventBus:IEventDispatcher; | |
[Inject] | |
public var key:IKey; | |
public function execute():void { | |
// starts LOCK process, passing a payload (the key) | |
// NB: any ongoing process will be cleared on acceptance of the new one. | |
eventBus.dispatchEvent( new ProcessEvent( ProcessEventTypes.LOCK, key ) ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fluent FSM
concept
The Fluent FSM is a network of nodes (States) linked together with directional edges (transitions). This network is abstracted from the application's logic by Processes. Processes allow transitions from State to State to be concatenated, depending on the State in which they are called.
Each State may have guards applied to them to forbid entry or exit, they also have three optional phases, entering, teardown and cancelled that can be mapped to the execution of an ICommand.
the big assumption
Transitions are synchronous, therefore any ICommands executed as a result of a phase dispatch must also be synchronous, in other words executed in parallel, not in sequence. Any asynchronicity must be off loaded to other functional areas / actors. It is the States that encapsulate Asynchronous behavior, not the Transitions or Processes.