Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Finite State Machine in Kotlin

License

NotificationsYou must be signed in to change notification settings

open-jumpco/kfsm

Repository files navigation

This work is licensed underApache License 2.0

This is a small implementation of an FSM in Kotlin.

Getting Started

The state machine implementation supports events triggering transitions from one state to another while performing an optional action as well as entry and exit actions.

Features

  • Event driven state machine.

  • External and internal transitions

  • State entry and exit actions.

  • Default state actions.

  • Default entry and exit actions.

  • Determine allowed events.

  • Multiple state maps with push / pop transitions

  • Automatic transitions

  • Externalisation of state.

  • Typed event parameters and return values.

Todo

  • ✓ Multiple state maps

  • ✓ Push / pop transitions

  • ✓ Automatic transitions

  • ✓ Externalisation of state

  • ✓ Typed event parameters

  • ✓ Typed event return values

  • ✓ Simple Visualization

  • ✓ Detail Visualization

  • ✓ Gradle Plugin for Visualization

  • ✓ Timeouts

  • ✓ Corountines

  • ❏ Different type of contexts for Nested statemaps

Quick Tutorial

This is the classic turnstile FSM model from [SMC](http://smc.sourceforge.net/)

Simple turnstile example

Assume we and to manage the state on a simple lock.We want to ensure that thelock() function is only called when the lock is not locked and we wantunlock() to be called when locked.

Then we use the DSL to declare a definition of a statemachine matching the diagram:

State Diagram

Turnstile state diagram

State Table

Start StateEventEnd StateAction

LOCKED

PASS

LOCKED

alarm

LOCKED

COIN

UNLOCKED

unlock

UNLOCKED

PASS

LOCKED

lock

UNLOCKED

COIN

UNLOCKED

returnCoin

Context class

classTurnstile(varlocked:Boolean =true) {fununlock() {assert(locked) {"Cannot unlock when not locked" }println("Unlock")        locked=false    }funlock() {assert(!locked) {"Cannot lock when locked" }println("Lock")        locked=true    }funalarm() {println("Alarm")    }funreturnCoin() {println("Return coin")    }overridefuntoString():String {return"Turnstile(locked=$locked)"    }}

Enums for States and Events

We declare 2 enums, one for the possible states and one for the possible events.

enumclassTurnstileStates {LOCKED,UNLOCKED}enumclassTurnstileEvents {COIN,PASS}

Packaged definition and execution

classTurnstileFSM(turnstile:Turnstile) {privateval fsm= definition.create(turnstile)funcoin()= fsm.sendEvent(TurnstileEvents.COIN)funpass()= fsm.sendEvent(TurnstileEvents.PASS)companionobject {privateval definition= stateMachine(TurnstileStates.values().toSet(),TurnstileEvents::class,Turnstile::class        ) {            initialState {if (locked)TurnstileStates.LOCKEDelseTurnstileStates.UNLOCKED            }            default {                onEntry { startState, targetState, _->println("entering:$startState ->$targetState for$this")                }// default transition will invoke alarm                action { state, event, _->println("Default action for state($state) -> event($event) for$this")                    alarm()                }                onExit { startState, targetState, _->println("exiting:$startState ->$targetState for$this")                }            }// when current state is LOCKED            whenState(TurnstileStates.LOCKED) {// external transition on COIN to UNLOCKED state                onEvent(TurnstileEvents.COIN toTurnstileStates.UNLOCKED) {                    unlock()                }            }// when current state is UNLOCKED            whenState(TurnstileStates.UNLOCKED) {// internal transition on COIN                onEvent(TurnstileEvents.COIN) {                    returnCoin()                }// external transition on PASS to LOCKED state                onEvent(TurnstileEvents.PASS toTurnstileStates.LOCKED) {                    lock()                }            }        }.build()    }}

With this definition we are saying:When the state isLOCKED and on aCOIN event then transition toUNLOCKED and execute the lambda which is treatedas a member of the context{ unlock() }

When the state isLOCKED and on eventPASS we perform the actionalarm() without changing the end state.

Usage

Then we instantiate the FSM and provide a context to operate on:

val turnstile=Turnstile()val fsm=TurnstileFSM(turnstile)

Now we have a context that is independent of the FSM.

Sending events may invoke actions:

// State state is LOCKEDfsm.coin()// Expect unlock action end state is UNLOCKEDfsm.pass()// Expect lock() action and end state is LOCKEDfsm.pass()// Expect alarm() action and end state is LOCKEDfsm.coin()// Expect unlock() and end state is UNLOCKEDfsm.coin()// Expect returnCoin() and end state is UNLOCKED

This model means the FSM can be instantiated as needed if the context has values that represent the state. The idea is that the context will properly maintain it’s internal state.

The FSM can derive the formal state from the value(s) of properties of the context.

TheDocumentation contains more detail on creating finite state machine implementations.

The documentation contains examples for:

Repository

Use this repository for SNAPSHOT builds. Releases are on Maven Central

repositories {    maven {        url'https://oss.sonatype.org/content/groups/public'    }}

Dependencies

KMP Projects

The dependency used in common modules.

dependencies {    implementation'io.jumpco.open:kfsm:1.9.0-RC1'}

JVM Projects

dependencies {    implementation'io.jumpco.open:kfsm-jvm:1.9.0-RC1'}

KotlinJS Projects

dependencies {    implementation'io.jumpco.open:kfsm-js:1.9.0-RC1'}

Kotlin/Native Projects using LinuxX64

dependencies {    implementation'io.jumpco.open:kfsm-linuxX64:1.9.0-RC1'}

Kotlin/Native Projects using MinGW64

dependencies {    implementation'io.jumpco.open:kfsm-mingwX64:1.9.0-RC1'}

Kotlin/Native Projects using macOS

dependencies {    implementation'io.jumpco.open:kfsm-macosX64:1.9.0-RC1'}

Visualisation

For more information about visualization options usekfsm-io.jumpco.open.kfsm.viz

Plantuml Examples

Turnstile FSM

turnstile

Paying Turnstile FSM

paying turnstile

Secure Turnstile FSM

secure turnstile

Packer Reader FSM

packet reader

Questions:

  • Should entry / exit actions receive state or event as arguments?

  • Should default actions receive state or event as arguments?

  • Is there a more elegant way to define States and Events using sealed classes?

  • Are any features missing from the implementation?


[8]ページ先頭

©2009-2025 Movatter.jp