2009-10-15 48 views
4

概述:使用的状态模式一“变化” - C++

我想提高我使用状态模式的程序设计。我将发布一个关于这个问题的简要描述,一个当前设计的类图/描述的图像,以及相关类的标题代码。

问题:

我使用某个程序的状态模式的变化。在这个变体中,我有一个'控制器',它使用了两个抽象类'状态'和'事件',这两个抽象类扩展了几种具体类型。这两个抽象类用于对根据事件类型和当前状态而变化的“事件”进行响应。每个状态都有一个“处理程序”函数,它被重载以获取每个具体的事件类型。

'控制器'包含一个类型为'event'(抽象类)的队列,其中包含已发生的'events'(具体类)列表。控制器每次处理一个事件,通过从队列中检索每个事件,并将其传递给状态处理程序以处理特定类型的事件。

问题是,为了获得正确的类型以将事件传递给状态的相应处理程序,我必须将downcast事件转换为正确的具体类型。目前,我通过向每个具体事件类型实现的类'state'(getType())添加一个方法来完成此任务,并返回一个表示该事件类型的整数。然而,这种做法非常“不雅”,并导致使用枚举来驱动“切换”块和“向下转换” - 这不是很好的设计实践。

我该如何改变这种设计,让事件传递到更优雅的状态?

类图

Class diagram

标题代码

/***** 
* CONTROLLER (driver) CLASS 
*/ 
queue<event> events; //gets populated by other threads that hold reference to it 
state* currentState; 
vector<state*> allStates; 
allStates.push_back(new state_1(&allStates)); // passes reference to 'allStates' to each state 
allStates.push_back(new state_2(&allStates)); // so that it may return the 'next state' 
... 

while(true){ 
    event nextEvent; 
    state* nextState; 
    if(events.size() > 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->handle(*dynamic_cast<event_type_1*>(&nextEvent)); 
       break; 
      case 2: 
       state* nextState = currentState->handle(*dynamic_cast<event_type_1*>(&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<state*>* m_states; 
    public: 
     state(vector<state*>* 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); 
} 

回答

4

添加的抽象方法:

virtual state *transition(state *from) = 0; 

到事件。

,然后实现是在每个状态子类如下:

state *transition(state *from) 
{ 
    from->handle(this); 
} 

然后在循环只需拨打:

nextState = nextEvent->transition(currentState); 

编辑:

如果您事件模板类模板在其子类中,您可以在事件类本身中实现转换:

template <class subclass> class event 
{ 
    state *transition(state *from) 
    { 
     from->handle(dynamic_cast<subclass *>(this)); 
    } 
} 
+0

嘿, 我目前正在尝试您的建议... 如果我向类'事件'添加'transition(state * from)',这不会导致'循环依赖',其中类'event'和'state'是相互引用的吗? – simplyletgo 2009-10-15 14:16:55

+1

是的,他们都会互相引用,但没关系。您需要在课前事件前转发声明课程状态,即 课程状态; //前置声明 class event {...} – atomice 2009-10-15 14:46:13

+0

aha,我明白了!我甚至没有意识到你可以用C++中的类来做到这一点,这很酷。如果编译器在'event.h'和'state.h'中看到'class state'的定义,并且说'hell no',我会认为这会导致某种'重新定义问题'。 – simplyletgo 2009-10-15 15:03:38