如何避免垂头丧气? [英] How to avoid downcast?

查看:132
本文介绍了如何避免垂头丧气?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个状态模式的实现,其中每个状态都处理从事件队列中获取的事件.因此,基类State具有纯虚方法void handleEvent(const Event*).事件继承了Event基类,但是每个事件都包含其数据,该数据可以具有不同的类型(例如int,string等). handleEvent必须确定接收到的事件的运行时类型,然后执行 downcast 以便提取事件数据.事件是动态创建的,并存储在队列中(因此 upcasting 在这里进行...).

I have an implementation of a State Pattern where each state handles events it gets from a event queue. Base State class therefore has a pure virtual method void handleEvent(const Event*). Events inherit base Event class but each event contains its data that can be of a different type (e.g. int, string...or whatever). handleEvent has to determine the runtime type of the received event and then perform downcast in order to extract event data. Events are dynamically created and stored in a queue (so upcasting takes place here...).

我知道向下转换是不良设计的标志,但是在这种情况下是否可以避免?我正在考虑访问者模式,基类State会在其中包含每个事件的虚拟处理程序,但是再次需要在代码片段中进行向下转换,以使事件从队列中出队并将其传递到当前状态. (至少在这种情况下,大switch(eventID)只能在一个地方...). 访问者模式是否是避免向下转换的最佳方法(最佳实践)?

I know that downcasting is a sign of a bad design but is it possible to avoid it in this case? I am thinking of Visitor Pattern where base class State would contain virtual handlers for each event but then again downcast will need to take place in the piece of code which dequeues event from a queue and passes it to the current state. (At least in this case big switch(eventID) would be only at one place...). Is Visitor Pattern the best way (best practice) to avoid downcasting?

这是伪代码(在此示例中,我通过了boost::shared_ptr,但向下转换仍然会发生):

Here is the pseudo-code (I am passing boost::shared_ptr in this example but downcasting happens anyway):

enum EventID
{
   EVENT_1,
   EVENT_2,
   ...
};

class Event
{
   EventID id;
public:
   Event(EventID id):id(id){}
   EventID id() const {return id;}
   virtual ~Event() = 0;
};

class Event1 : public Event
{
   int n;
public:
   Event1(int n):Event(EVENT_1), n(n){}
   int getN() const {return n;}
};

class Event2 : public Event
{
   std::string s;
public:
   Event2(std::string s):Event(EVENT_2), s(s){}
   std::string getS() const {return s;}
};

typedef boost::shared_ptr<Event> EventPtr;

class State
{
   ...
public:
   ...
   virtual ~State() = 0;
   virtual void handleEvent(const EventPtr& pEvent) = 0;
};

class StateA : public State
{
   ...
public:
   void handleEvent(const EventPtr& pEvent)
   {
      switch(pEvent->id())
      {
         case EVENT_1:        
            int n = boost::static_pointer_cast<Event1>(pEvent)->getN();
            ...
            break;
         case EVENT_2:
            std::string s = boost::static_pointer_cast<Event2>(pEvent)->getS();
            ...
            break;
         ... 

      }
   }   
}

推荐答案

由于采用了双重调度策略,典型的访客模式不会降低性能:

The typical visitor pattern performs no downcast, thanks to a double-dispatch strategy:

// Visitor.hpp
class EventBar;
class EventFoo;

class Visitor {
public:
    virtual void handle(EventBar const&) = 0;
    virtual void handle(EventFoo const&) = 0;
};

// Event.hpp
class Visitor;

class Event {
public:
    virtual void accept(Visitor&) const = 0;
};

实现:

// EventBar.hpp
#include <Event.hpp>

class EventBar: public Event {
public:
    virtual void accept(Visitor& v);
};

// EventBar.cpp
#include <EventBar.hpp>
#include <Visitor.hpp>

void EventBar::accept(Visitor& v) {
    v.handle(*this);
}

此处的关键点是,在v.handle(*this)中,*this的静态类型是EventBar const&,它在Visitor中选择了正确的virtual void handle(EventBar const&) = 0重载.

The key point here is that in v.handle(*this) the static type of *this is EventBar const&, which selects the correct virtual void handle(EventBar const&) = 0 overload in Visitor.

这篇关于如何避免垂头丧气?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆