1
votes

I am working with a Protocol Designing code in c++ and need help regarding state machine designing.

All the state machines that we have are of an identical nature. Each state machine has certain states (S1, S2, etc), and each state can accept only certain types of events (E1, E2 etc.). Based on the result of the processing of an event the machine moves to a next state.

For example, from a state S1 and for event E1, the machine can move to S2 or S3. I studied the State Design pattern but it suggest that all the states ( derived state classes) should implement all the actions the state machine can perform or the base state class should implement such actions. In my case individual state can process only certain events so I believe State design pattern would not be applicable.

Can you suggest what would be best way/pattern to implement such machines.

1
So what should happen when you are in state S1 and you receive the unhandled event E62? - Bill Lynch
This question appears to be off-topic because it is about software design, which would be better on programmers.stackexchange.com - jamessan
Have you looked at Boost Statechart? Not sure it's exactly what you need/want, but it might be useful. - Jerry Coffin
@sharth If I receive an event E62 in state S1 and S1 is not meant to handle E62 then that means the event has been incorrectly generated and we will discard the event and simply log an error. - chandra.v
State machines are not a big deal. If they change very infrequently, you can make use of the fact that every state machine corresponds to a regular expression, and every regular expression corresponds to a simple structured program (with if and while). - Mike Dunlavey

1 Answers

1
votes

According to the "gang of four", the State design pattern is applicable when an object's behaviour depends on its state and it must change behaviour at run time, depending on that state.

The description of your state machine, which changes state based on an event, seems to match this description.

class StateMachine {    // state machine that processes events received
    State *s; 
public:  
    StateMachine();         // constructor: here you shall set initial state
    void process (Event* e); // processes the event and sets the next state
    bool isReady ();        // example of other requests
};

The principle of this pattern is to have an abstract base class, defining all the potential states dependent "actions" that StateMachine may delegate to a state.

class State {
public: 
      virtual void process (StateMachine *m, Event* e)=0;    // called by state machine /  pure virtual MUST be implemented in concrete state 
      virtual bool isReady(StateMachine *m);  // example  
      ...                               // other "actions"     
};

The interface between your state and the state machine would then be easy to define. For example:

void StateMachine::Process (Event *e) {
     s->Process (this, e);   // calls the Process() of the current state 
}

Derived concrete states shall then implement the different behaviours. As this *pattern works with virtual functions in C++, all the actions must be defined for each concrete state (either in base class or in the derived). This is a direct consequence of defining virtual functions.

But for actions that are not relevant for all the states, you may have a default action, either doing nothing, or triggering an error (error message, exception, ...). It depends on your general design, whether you prevent such situations to happen or not.

For example:

bool State::isReady(StateMachine *m) {  // if this request is only relevant for a couple of states
   throw std::exception ("unauthorized request");   // trigger an exception if it happens
   return false;
}    // this is done by default, except for concrete state that defines somtehing else 

According to your description, I would really go for the state pattern.