Last active
March 23, 2016 10:00
-
-
Save kristopherjohnson/4bcb89e07a5ece10e305 to your computer and use it in GitHub Desktop.
Swift implementation of Robert C. Martin's turnstile state-machine example
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
// Implementation of Robert C. Martin's turnstile state-machine example | |
/// Defines the "events" that can be invoked on a turnstile-like object. | |
protocol TurnstileEventHandler { | |
func onCoin() | |
func onPass() | |
} | |
/// Defines the "actions" that a turnstile can take due to an event or state transition. | |
protocol TurnstileActionDelegate: class { | |
func unlock() | |
func alarm() | |
func lock() | |
func thankYou() | |
} | |
/// Finite state machine that accepts `TurnstileEventHandler` events | |
/// and invokes actions on a `TurnstileActionDelegate`. | |
class TurnstileStateMachine { | |
/// Base class for states. | |
private class State { | |
weak var stateMachine: TurnstileStateMachine? | |
init(_ stateMachine: TurnstileStateMachine?) { | |
self.stateMachine = stateMachine | |
} | |
func changeState(newState: State) { | |
stateMachine?.state = newState | |
} | |
func onEntry() { print("No entry action") } | |
func onCoin() { print("No transition for coin") } | |
func onPass() { print("No transition for pass") } | |
func unlock() { stateMachine?.unlock() } | |
func alarm() { stateMachine?.alarm() } | |
func lock() { stateMachine?.lock() } | |
func thankYou() { stateMachine?.thankYou() } | |
} | |
/// Definitions of `locked` state transitions and actions. | |
private class Locked: State { | |
override func onEntry() { lock() } | |
override func onCoin() { changeState(Unlocked(stateMachine)) } | |
override func onPass() { alarm() } | |
} | |
/// Definitions of `unlocked` state transitions and actions. | |
private class Unlocked: State { | |
override func onEntry() { unlock() } | |
override func onCoin() { thankYou() } | |
override func onPass() { changeState(Locked(stateMachine)) } | |
} | |
private var state: State! { | |
didSet { | |
if state != nil { state.onEntry() } | |
} | |
} | |
weak var delegate: TurnstileActionDelegate? | |
init() { | |
self.state = Locked(self) | |
} | |
} | |
extension TurnstileStateMachine: TurnstileEventHandler { | |
func onCoin() { state.onCoin() } | |
func onPass() { state.onPass() } | |
} | |
extension TurnstileStateMachine: TurnstileActionDelegate { | |
func unlock() { delegate?.unlock() } | |
func alarm() { delegate?.alarm() } | |
func lock() { delegate?.lock() } | |
func thankYou() { delegate?.thankYou() } | |
} | |
/// A concrete implementation of a turnstile, which accepts | |
/// `TurnstileEventHandler` events and implements the | |
/// `TurnstileActionDelegate` actions. | |
class Turnstile { | |
let stateMachine = TurnstileStateMachine() | |
init() { | |
stateMachine.delegate = self | |
} | |
} | |
/// The public interface to `Turnstile`, which just passes the event to its state machine. | |
extension Turnstile: TurnstileEventHandler { | |
func onCoin() { stateMachine.onCoin() } | |
func onPass() { stateMachine.onPass() } | |
} | |
/// The actions triggered by state machine transitions. | |
extension Turnstile: TurnstileActionDelegate { | |
func unlock() { print("unlock") } | |
func alarm() { print("alarm") } | |
func lock() { print("lock") } | |
func thankYou() { print("thankYou") } | |
} | |
// Test | |
let t: TurnstileEventHandler = Turnstile() | |
t.onCoin() // "unlock" | |
t.onPass() // "lock" | |
t.onCoin() // "unlock" | |
t.onCoin() // "thankYou" | |
t.onPass() // "lock" | |
t.onPass() // "alarm" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Robert C Martin's "UML Tutorial: Finite State Machines": http://www.objectmentor.com/resources/articles/umlfsm.pdf