Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing a 'variation' on State Pattern - C++
    primarykey
    data
    text
    <p><b> Overview: </b> </p> <p>I am trying to improve the design of a program that I am using state pattern for. I will post a brief description of the problem, an image of the class diagram/description of the current design, followed by header code for the relevant classes.</p> <p><b>Problem: </b></p> <p>I'm using a variation of the State Pattern for a program. In this variation, I have a 'controller' that utilizes two abstract classes, 'state' and 'event', which several concrete types are extended from both. These two abstract classes are used to carry out responses to 'events' that vary based upon the type of event, and the current state. Each state has a 'handler' function that is overloaded to take each concrete event type.</p> <p>The 'controller' contains a queue of type 'event' (the abstract class), which contains the list of of 'events' (concrete classes) that have occurred. The controller 'processes' each event one at a time, by retrieving it from the queue, and passing it to the state's handler for that particular type of event.</p> <p>The problem is that in order to get the correct type to pass the event to the state's appropriate handler, I have to <b>downcast</b> the event to the correct concrete type. Currently, I accomplish this by adding a method to class 'state' (getType()) which is implemented by each concrete event type, and returns an integer that represents that event type. However, this practice is very 'un-elegant' and results in using enums to drive 'switch' blocks and 'downcasting' - which are not very good design practices.</p> <p>How can I change this design to make the passing of events to states more elegant? </p> <p><b>Class Diagram</b></p> <p><img src="https://i.stack.imgur.com/q48V4.jpg" alt="Class diagram"></p> <p><b>Header Code</b></p> <pre><code>/***** * CONTROLLER (driver) CLASS */ queue&lt;event&gt; events; //gets populated by other threads that hold reference to it state* currentState; vector&lt;state*&gt; allStates; allStates.push_back( new state_1(&amp;allStates) ); // passes reference to 'allStates' to each state allStates.push_back( new state_2(&amp;allStates) ); // so that it may return the 'next state' ... while( true ){ event nextEvent; state* nextState; if( events.size() &gt; 0 ){ nextEvent = events.front(); //Get next Event events.pop(); //remove from queue switch( nextEvent.getType() ){ //determine 'concrete type' based on 'getType method' case 1: //Downcast to concrete state type, and let state handle event nextState = currentState-&gt;handle( *dynamic_cast&lt;event_type_1*&gt;(&amp;nextEvent) ); break; case 2: state* nextState = currentState-&gt;handle( *dynamic_cast&lt;event_type_1*&gt;(&amp;nextEvent) ); break; ... } //Transition to next state currentState = nextState; else Sleep(5); // } /***** * EVENT CLASSES */ class event{ public: virtual int getType(); } class event_type_1 : public event{ public: int getType(){ return 1; }; int specializedFunc1(); double specializedFunc2(); } class event_type_2 : public event{ public: int getType(){ return 2; }; std::string specializedFunc3(); } /***** * STATE CLASSES */ class state{ protected: vector&lt;state*&gt;* m_states; public: state( vector&lt;state*&gt;* p_states ){ m_states = p_states; }; virtual state* handle( event_type_1 ); virtual state* handle( event_type_2 ); } class state_1 : public state{ public: state* handle( event_type_1 ); state* handle( event_type_2 ); } class state_2 : public state{ public: state* handle( event_type_1 ); state* handle( event_type_2 ); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload