# State Pattern

version 2.4.19

The State Pattern provides a structured approach to partitioning the behaviour within complex systems. The overall behaviour of a system is partitioned into well-defined states. Typically, each state is implemented by a class. The overall system behaviour can be determined firstly by knowing the current state of the system; secondly, by understanding the behaviour possible while in that state (as embodied in the methods of the class corresponding to that state).

## 1. Example

Here is an example:

    class Client {
        def context = new Context()
        def connect() {
            context.state.connect()
        }
        def disconnect() {
            context.state.disconnect()
        }
        def send_message(message) {
            context.state.send_message(message)
        }
        def receive_message() {
            context.state.receive_message()
        }
    }

    class Context {
        def state = new Offline(this)
    }

    class ClientState {
        def context
        ClientState(context) {
            this.context = context
            inform()
        }
    }

    class Offline extends ClientState {
        Offline(context) {
            super(context)
        }
        def inform() {
            println "offline"
        }
        def connect() {
            context.state = new Online(context)
        }
        def disconnect() {
            println "error: not connected"
        }
        def send_message(message) {
            println "error: not connected"
        }
        def receive_message() {
            println "error: not connected"
        }
    }

    class Online extends ClientState {
        Online(context) {
            super(context)
        }
        def inform() {
            println "connected"
        }
        def connect() {
            println "error: already connected"
        }
        def disconnect() {
            context.state = new Offline(context)
        }
        def send_message(message) {
            println "\"$message\" sent"
        }
        def receive_message() {
            println "message received"
        }
    }

    client = new Client()
    client.send_message("Hello")
    client.connect()
    client.send_message("Hello")
    client.connect()
    client.receive_message()
    client.disconnect()

Here is the output:

    offline
    error: not connected
    connected
    "Hello" sent
    error: already connected
    message received
    offline

One of the great things about a dynamic language like Groovy though is that we can take this example and express it in many different ways depending on our particular needs. Some potential variations for this example are shown below.

## 2. Variation 1: Leveraging Interface-Oriented Design

One approach we could take is to leverage Interface-Oriented Design. To do this, we could introduce the following interface:

    interface State {
        def connect()
        def disconnect()
        def send_message(message)
        def receive_message()
    }

Then our `Client`, `Online` and 'Offline` classes could be modified to implement that interface, e.g.:

    class Client implements State {
      // ... as before ...
    }

    class Online implements State {
      // ... as before ...
    }

    class Offline implements State {
      // ... as before ...
    }

You might ask: Haven’t we just introduced additional boilerplate code? Can’t we rely on duck-typing for this? The answer is 'yes' and 'no'. We can get away with duck-typing but one of the key intentions of the state pattern is to partition complexity. If we know that the client class and each state class all satisfy one interface, then we have placed some key boundaries around the complexity. We can look at any state class in isolation and know the bounds of behaviour possible for that state.

We don’t have to use interfaces for this, but it helps express the intent of this particular style of partitioning and it helps reduce the size of our unit tests (we would have to have additional tests in place to express this intent in languages which have less support for interface-oriented design).

## 3. Variation 2: Extract State Pattern Logic

Alternatively, or in combination with other variations, we might decide to extract some of our State Pattern logic into helper classes. For example, we could define the following classes in a state pattern package/jar/script:

    abstract class InstanceProvider {
        static def registry = GroovySystem.metaClassRegistry
        static def create(objectClass, param) {
            registry.getMetaClass(objectClass).invokeConstructor([param] as Object[])
        }
    }

    abstract class Context {
        private context
        protected setContext(context) {
            this.context = context
        }
        def invokeMethod(String name, Object arg) {
            context.invokeMethod(name, arg)
        }
        def startFrom(initialState) {
            setContext(InstanceProvider.create(initialState, this))
        }
    }

    abstract class State {
        private client

        State(client) { this.client = client }

        def transitionTo(nextState) {
            client.setContext(InstanceProvider.create(nextState, client))
        }
    }

This is all quite generic and can be used wherever we want to introduce the state pattern. Here is what our code would look like now:

    class Client extends Context {
        Client() {
            startFrom(Offline)
        }
    }

    class Offline extends State {
        Offline(client) {
            super(client)
            println "offline"
        }
        def connect() {
            transitionTo(Online)
        }
        def disconnect() {
            println "error: not connected"
        }
        def send_message(message) {
            println "error: not connected"
        }
        def receive_message() {
            println "error: not connected"
        }
    }

    class Online extends State {
        Online(client) {
            super(client)
            println "connected"
        }
        def connect() {
            println "error: already connected"
        }
        def disconnect() {
            transitionTo(Offline)
        }
        def send_message(message) {
            println "\"$message\" sent"
        }
        def receive_message() {
            println "message received"
        }
    }

    client = new Client()
    client.send_message("Hello")
    client.connect()
    client.send_message("Hello")
    client.connect()
    client.receive_message()
    client.disconnect()

You can see here the `startFrom` and `transitionTo` methods begin to give our example code a DSL feel.

## 4. Variation 3: Bring on the DSL

Alternatively, or in combination with other variations, we might decide to fully embrace a Domain Specific Language (DSL) approach to this example.

We can define the following generic helper functions (first discussed here):

    class Grammar {
        def fsm

        def event
        def fromState
        def toState

        Grammar(a_fsm) {
            fsm = a_fsm
        }

        def on(a_event) {
            event = a_event
            this
        }

        def on(a_event, a_transitioner) {
            on(a_event)
            a_transitioner.delegate = this
            a_transitioner.call()
            this
        }

        def from(a_fromState) {
            fromState = a_fromState
            this
        }

        def to(a_toState) {
            assert a_toState, "Invalid toState: $a_toState"
            toState = a_toState
            fsm.registerTransition(this)
            this
        }

        def isValid() {
            event && fromState && toState
        }

        public String toString() {
            "$event: $fromState=>$toState"
        }
    }

    class FiniteStateMachine {
        def transitions = [:]

        def initialState
        def currentState

        FiniteStateMachine(a_initialState) {
            assert a_initialState, "You need to provide an initial state"
            initialState = a_initialState
            currentState = a_initialState
        }

        def record() {
            Grammar.newInstance(this)
        }

        def reset() {
            currentState = initialState
        }

        def isState(a_state) {
            currentState == a_state
        }

        def registerTransition(a_grammar) {
            assert a_grammar.isValid(), "Invalid transition ($a_grammar)"
            def transition
            def event = a_grammar.event
            def fromState = a_grammar.fromState
            def toState = a_grammar.toState

            if (!transitions[event]) {
                transitions[event] = [:]
            }

            transition = transitions[event]
            assert !transition[fromState], "Duplicate fromState $fromState for transition $a_grammar"
            transition[fromState] = toState
        }

        def fire(a_event) {
            assert currentState, "Invalid current state '$currentState': passed into constructor"
            assert transitions.containsKey(a_event), "Invalid event '$a_event', should be one of ${transitions.keySet()}"
            def transition = transitions[a_event]
            def nextState = transition[currentState]
            assert nextState, "There is no transition from '$currentState' to any other state"
            currentState = nextState
            currentState
        }
    }

Now we can define and test our state machine like this:

    class StatePatternDslTest extends GroovyTestCase {
        private fsm

        protected void setUp() {
            fsm = FiniteStateMachine.newInstance('offline')
            def recorder = fsm.record()
            recorder.on('connect').from('offline').to('online')
            recorder.on('disconnect').from('online').to('offline')
            recorder.on('send_message').from('online').to('online')
            recorder.on('receive_message').from('online').to('online')
        }

        void testInitialState() {
            assert fsm.isState('offline')
        }

        void testOfflineState() {
            shouldFail{
                fsm.fire('send_message')
            }
            shouldFail{
                fsm.fire('receive_message')
            }
            shouldFail{
                fsm.fire('disconnect')
            }
            assert 'online' == fsm.fire('connect')
        }

        void testOnlineState() {
            fsm.fire('connect')
            fsm.fire('send_message')
            fsm.fire('receive_message')
            shouldFail{
                fsm.fire('connect')
            }
            assert 'offline' == fsm.fire('disconnect')
        }
    }

This example isn’t an exact equivalent of the others. It doesn’t use predefined `Online` and `Offline` classes. Instead it defines the entire state machine on the fly as needed. See the previous reference for more elaborate examples of this style.

See also: Model-based testing using ModelJUnit