Created
February 21, 2018 13:32
-
-
Save zag/69997ac130c55e0c01f09acdf65eefd2 to your computer and use it in GitHub Desktop.
simple 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
// | |
// +-----+ | |
// | off | | |
// +-----+ | |
// | | |
// v | |
// +--------+ | |
// | red | <- + | |
// +--------+ / | |
// | / | |
// v / | |
// +--------+ / | |
// | yellow | / | |
// +--------+ / | |
// | / | |
// V / | |
// +-------+ / | |
// | green | / | |
// +-------+ / | |
// | / | |
// +----------+ | |
// | |
// | |
// 1) базовое устройство | |
// 2) данные стейта | |
// 3) работа с сайд эффектами | |
// 4) работа ui | |
Cancelable { | |
fun cancel() | |
} | |
interface Event {} | |
object Tick : Event {} | |
object Start : Event {} | |
object Stop : Event {} | |
data class LightboxSnapshot( | |
val stateId: String, // off, red, green, yellow | |
val meta: Meta | |
) : Event | |
interface SnapshotStore { | |
fun write(snapshot: LightboxSnapshot): Unit | |
fun read(): LightboxSnapshot | |
} | |
interface LogStore { | |
fun append(event: Event) | |
fun snapshot(snapshot: LightboxSnapshot) | |
fun readAll(): List[Event] | |
} | |
interface Listener { | |
fun onOff() | |
fun onRed() | |
fun onYellow() | |
fun onGreen() | |
} | |
interface EventBox { | |
fun listen(listener: Listener) | |
fun triggerOff() | |
fun triggerRed() | |
fun triggerYellow() | |
fun triggerGreen() | |
} | |
class Lightbox { | |
private var state : State = OffState() | |
private val store : SnapshotStore = {...} | |
public val eventBox : EventBox = {...} | |
fun handle(event: Event) { | |
state = state.handle(event) | |
} | |
fun snapshot() { | |
var stateId = state.className | |
var meta = state.meta | |
var snapshot = LightboxSnapshot(stateId, meta) | |
store.write(snapshot) | |
} | |
fun restore() { | |
for(event in store.readAll()) { | |
handle(event) | |
} | |
} | |
fun ticksCount: Long = state.meta.counter | |
fun timeout(() -> Unit, time: Long): Cancelable | |
data class Meta(val counter: Long) { | |
fun inc(): Meta { | |
return Meta(counter + 1) | |
} | |
} | |
abstarct class State(val meta: Meta) { | |
fun handle(event: Event) : State { | |
store.append(event) | |
return when(event) { | |
is Tick -> handleTick(event) | |
is Start -> handleStart(event) | |
is Stop -> handleStop(event) | |
is LightboxSnapshot -> restore(event) | |
else -> | |
log.error("unexpected event: $event") | |
state | |
} | |
} | |
open fun handleTick(event: Tick) : State | |
open fun handleStart(event: Start) : State | |
open fun handleStop(event: Stop) : State | |
fun restore(snapshot: Snapshot): State { | |
val snapshot = store.read() | |
return when(snapshot.stateId) { | |
"off" -> OffState() | |
"red" -> RedState(snapshot.meta) | |
"yellow" -> YellowState(snapshot.meta) | |
"green" -> GreenOffState(snapshot.meta) | |
} | |
} | |
} | |
class OffState : State(Meta(0)) { | |
init { eventBox.triggerOff() } | |
override fun handleTick(event: Tick) : State { | |
log.debug("ignore tick in off state") | |
return this | |
} | |
override fun handleStart(event: Start) : State { | |
return gotoRed() | |
} | |
override fun handleStop(event: Stop) : State { | |
log.debug("ignore stop in off state") | |
return this | |
} | |
fun gotoRed(): State = RedState(meta) | |
} | |
class RedState(meta: Meta) : State(meta) { | |
init { eventBox.triggerRed() } | |
var tick = timeout(() -> Lightbox.this.handle(Tick), 10_000) | |
override fun handleTick(event: Tick) : State { | |
return gotoYellow() | |
} | |
override fun handleStart(event: Start) : State { | |
log.debug("ignore stop in red state") | |
return this | |
} | |
override fun handleStop(event: Stop) : State { | |
tick.cancel() | |
return gotoOff() | |
} | |
fun gotoYellow(): State = YellowState(meta.inc()) | |
fun gotoOff(): State = OffState() | |
} | |
class YellowState(meta: Meta) : State(meta) { | |
init { eventBox.triggerYellow() } | |
var tick = timeout(() -> Lightbox.this.handle(Tick), 10_000) | |
override fun handleTick(event: Tick) : State { | |
return gotoGreen() | |
} | |
override fun handleStart(event: Start) : State { | |
log.debug("ignore stop in yellow state") | |
return this | |
} | |
override fun handleStop(event: Stop) : State { | |
tick.cancel() | |
return gotoOff() | |
} | |
fun gotoGreen(): State = GreenState(meta.inc()) | |
fun gotoOff(): State = OffState() | |
} | |
class GreenState(meta: Meta) : State(meta) { | |
init { eventBox.triggerGreen() } | |
var tick = timeout(() -> Lightbox.this.handle(Tick), 10_000) | |
override fun handleTick(event: Tick) : State { | |
return gotoRed() | |
} | |
override fun handleStart(event: Start) : State { | |
log.debug("ignore stop in green state") | |
return this | |
} | |
override fun handleStop(event: Stop) : State { | |
tick.cancel() | |
return gotoOff() | |
} | |
fun gotoRed(): State = RedState(meta.inc()) | |
fun gotoOff(): State = OffState() | |
} | |
} | |
val state = YellowState(Meta(20)).gotoGreen() | |
assert state.meta.counter = 21 | |
val fsm = Lightbox() | |
fsm.eventBox.listen(new Listener { | |
fun onOff() { logger.info("off!") } | |
fun onRed() { logger.info("ref!") } | |
fun onYellow() { logger.info("yellow!") } | |
fun onGreen() { logger.info("green!") } | |
}) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment