Search code examples
c++design-patternstransitionstate-pattern

GOF State Pattern State Transition Implementation Issues


Firstly, can anyone explain how a state object can be shared when the state object has no instance variables ?

This text is taken from GOF, page 308, item 3 (consequences section):

The state object can be shared. If state objects have no instance variabkes - that is, the state they represent is encoded entirely in their type - then contexts can share a state object. When states are shared in this way, they are essentially flyweight.

Can anyone explain this text ?

Secondly, what are the approaches to the state transition decision? I mean the decision of which next state to propagate?

Please help. Thanks.


Solution

  • In the state pattern you have an represent the state of an object by using state-objects. These state-objects represent a certain state, but they do not have any mutable state of their own. This means they never change. Therefore, any number of objects can use the same state-object at the same time (even from different threads). If the state-object had mutable state, other objects would have to worry about their state-object being changed from elsewhere.

    The using of one object instance by many others can be seen as an instance of the flyweight-pattern.

    As for the second part of your question, here is an example:

    class SomeStateMachine;
    
    class AbstractState {
        // abstract baseclass for all state-classes
        void input(const std::string & data, SomeStateMachine & caller) = 0;
    }
    
    class FinalState : public AbstractState {
        FinalState * getInstance(); // always returns same instance
    }
    
    class InitialState : public AbstractState {
    public:
        InitialState * getInstance(); // always returns same instance
        void input(const std::string & data, SomeStateMachine & caller) {
            std::cout << data << std::endl;
            caller.m_State = FinalState::getInstance();
        }
    }
    
    class SomeStateMachine {
    public:
        SomeStateMachine() : m_State(InitialState::getInstance())
        void input(const std::string & data) {
            m_State->input(data, *this);
        }
    private:
        friend class InitialState;
        AbstractState * m_State;
    };
    

    So you basically pass a reference to the calling object to every method of your state-object. This way, the state-object is able to change the state of the caller when needed. This example might not be very beautiful, but I hope you get the idea.