设计模式以避免在消息传递中向下转换

Oli*_*eng 2 c++ templates design-patterns downcast template-specialization

基类MessageHandler具有派生类.他们想把信息传递给对方.消息可以是不同的类,但可以使其共享基类.每个人如何MessageHandler避免向下传播收到的消息?是否有可能receiveMessage在MessageHandler上做一些具有模板参数化虚拟函数效果的东西?

本质上,我试图用不向下转换的东西替换下面的代码,并且希望是编译时的东西:

// ...
virtual void MessageHandler::receiveMessage(Message &msg) = 0;
// ...

// to receive a message
void DerivedMessageHandler::receiveMessage(Message& msg)
{
    switch (msg.MsgType()) // enum
    {
        case Message::MessageType::A:
            MessageA& = dynamic_cast<MessageA&>(msg);
            break;

        case Message::MessageType::B:
            MessageB& = dynamic_cast<MessageB&>(msg);
            break;
        default:
            // don't process unknown messages
            break;
    }
}

// to send a message
list<MessageHandler> mhList;
// populate list
for (MessageHandler& mh : mhList)
{
    mh.receiveMessage(msg);
}
Run Code Online (Sandbox Code Playgroud)

我知道我不能这样做,但有点像

template <typename M>
void MessageHandler::receiveMessage(M& msg) {}
Run Code Online (Sandbox Code Playgroud)

每个人都DerivedMessageHandler专注于M?什么是干净利落地让每个处理程序在其支持的消息对象上工作的设计模式?

Nic*_*las 6

这很容易做到.通常有两种选择:

Boost.Variant

而不是传递派生类,只需枚举消息可能的类型.这些类型不需要彼此派生.将这些类型包装在boost :: variant中:

typedef boost::variant<MessageData1, MessageData2, MessageData3, ...> MessageData;
Run Code Online (Sandbox Code Playgroud)

请注意,这意味着必须可枚举可能的消息数据类型.Boost.Variant的访问方法可以轻松处理这些类型的对象,而无需确切知道它存储的类型.

Boost.Any

只需传递任何东西boost::any:

void MessageHandler::receiveMessage(const boost::any &msg)
{
  const MessageType1 *pMsg = boost::any_cast<MessageType1>(&msg);
  if(!pMsg)
    //Cannot process
    return;

  //Process message.
}
Run Code Online (Sandbox Code Playgroud)

boost::any就像一个类型安全void*.它会记住投入它的确切类型,任何试图将其转换为一些其他比什么是存储在它将会失败.boost::any可以存储任何东西,因此得名.

它还具有值语义,因此可以像其内容一样进行复制.