如何在运行时确定消息类型?
How to determine type of message in runtime?
目前我正在为我的游戏服务器编写消息处理系统。我正在使用双分派设计模式根据从数据缓冲区检索到的消息 ID 选择所需的处理程序。但是我 运行 遇到了以下问题:我需要确定消息的派生 class 以将其传递给双分派处理程序对象。我找到的唯一解决方案是在 base class 中编写一个带有开关的工厂方法,它将根据消息 id 创建所需的派生 class。
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));
}
};
如何改进我的设计以避免大开关语句?提前致谢。
您可以使用 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 protocol buffers 之类的工具来定义您的通信协议。
这将有助于通过有线(或无线)进行正确的版本控制和解析消息包(字节序中性)。
结合例如boost::asio or zeromq 对于传输处理,这应该为您提供最大的灵活性和适当的机制来分离通信的传输层和语义层。
目前我正在为我的游戏服务器编写消息处理系统。我正在使用双分派设计模式根据从数据缓冲区检索到的消息 ID 选择所需的处理程序。但是我 运行 遇到了以下问题:我需要确定消息的派生 class 以将其传递给双分派处理程序对象。我找到的唯一解决方案是在 base class 中编写一个带有开关的工厂方法,它将根据消息 id 创建所需的派生 class。
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));
}
};
如何改进我的设计以避免大开关语句?提前致谢。
您可以使用 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 protocol buffers 之类的工具来定义您的通信协议。
这将有助于通过有线(或无线)进行正确的版本控制和解析消息包(字节序中性)。
结合例如boost::asio or zeromq 对于传输处理,这应该为您提供最大的灵活性和适当的机制来分离通信的传输层和语义层。