首页 > 解决方案 > 如何在运行时确定消息的类型?

问题描述

目前我正在为我的游戏服务器编写消息处理系统。我正在使用双分派设计模式根据从数据缓冲区中检索到的消息 ID 来选择所需的处理程序。但是我遇到了以下问题:我需要确定消息的派生类以将其传递给双调度处理程序对象。我找到的唯一解决方案是在带有开关的基类中编写一个工厂方法,它将根据消息 ID 创建所需的派生类。

class Message
{
public:
    void dispatch(Handler& handler)
    {
        dispatchImpl(handler);
    }

protected:
    virtual void dispatchImpl(Handler& handler) = 0;
};

template <typename TDerived>
class BaseMessage : public Message 
{
public:
    BaseMessage(unsigned short messageId)
        : id(messageId) {};

    virtual ~BaseMessage() = default;

    unsigned short getId() const { return id; }

    static std::unique_ptr<Message> create(BitStream& data)
    {
        switch (data.ReadShort())
        {
            case 1: return std::make_unique<FirstMessage>();
            case 2: return std::make_unique<SecondMessage>();
            case 3: return std::make_unique<ThirdMessage>();
            // ...
        }
    }

protected:
    unsigned short id;

    virtual void dispatchImpl(Handler& handler) override
    {
        handler.handle(static_cast<TDerived&>(*this));
    }
};

如何改进我的设计以避免大开关语句?提前致谢。

标签: c++oopnetworkingmessagepacket

解决方案


您可以使用std::map<short,std::function<std::unique_ptr<Message> (BitStream& data)>并允许动态注册这些工厂函数:

std::map<short,std::function<std::unique_ptr<Message> (BitStream& data)> createMessageHandlers;

void registerCreateMessageHandler(short id,std::function<std::unique_ptr<Message> (BitStream& data)> fn) {
      createMessageHandlers[id] = fn;
}

并像使用它一样

registerCreateMessageHandler(1, [](BitStream& data) { return std::make_unique<FirstMessage>();});
registerCreateMessageHandler(2, [](BitStream& data) { return std::make_unique<SecondMessage>();});

您的消息类型构造函数可能应该将BitStream&用作构造函数参数。


您应该考虑使用像google 协议缓冲区这样的工具来定义您的通信协议。
这将有助于正确进行版本控制,并通过有线(或无线)解析消息包(字节序中性)。

与用于传输处理的boost::asiozeromq相结合,应该为您提供最大的灵活性和适当的机制来分离通信的传输层和语义层。


推荐阅读