2.9
全结构化消息解析器
基于现在的消息映射表和消息分发过程,消息处理器的各个消息处理函数只能接受类型为HalfStructuredMessageWrapper或者HalfStructuredMessageSmartPtr的参数。任一消息处理函数的实现框架如下:
|
void ExampleProcessor::OnMessage_X(HalfStructuredMessageWrapper
wrapper)
{
// (1) 如果需要,取出wrapper.pHalfMsg_的消息头的各个信息;
// (2) 逐步解析wrapper.pHalfMsg_的消息体;
// (3) 根据消息ID和消息体的内容决定如何处理该消息,如果需要
//
还得向该消息的源端回发应答消息,或者触发其他消息的发送。
}
|
也就是说,开发人员还得在处理消息的代码中加入解析当前消息之消息体的代码(或者是XML
DOM树,或者是二进制字节流),这不仅有点儿笨拙,也容易造成混乱,而且违背了单一职责原则(SRP)。我们应该设法将解析消息体的代码彻底分离出来。
理论上,一个业务消息应该对应一个唯一的消息解析过程和一个唯一的消息处理过程。在具体实现的时候,可以为每个消息安排一个消息处理器,或者几个消息可以共享同一个消息处理器,但是对应不同的处理函数(已经通过消息映射表实现);同时每个消息都应该安排一个专门的消息解析器,显然这个消息解析器不能共享,它就是全结构化消息解析器——把半结构化消息解析为完全的struct数据结构。既然全结构化消息解析器是每个消息专用的,因此可以与消息ID关联起来,显然消息映射表应该是做这件事情的好地方。另外,虽然每个业务消息的全结构化解析器最终还得应用层的开发人员来实现,但是可以让框架来自动调用,这正是接口类和虚函数最擅长做的事情。为此,我们定义全结构化消息解析器接口如下:
|
class FullStructuredMessageParser
{
public:
virtual
FullStructuredMessageSmartPtr \
Parse(HalfStructuredMessageSmartPtr pHalfMsg) = 0;
};
|
用来解析每个业务消息的全结构化消息解析器从FullStructuredMessageParser派生并实现Parse()函数,返回的智能指针指向具体的全结构化消息。FullStructuredMessage是所有全结构化消息的基类,定义如下:
|
struct FullStructuredMessage
{
virtual
~FullStructuredMessage() = 0 { }
MessageHeaderSmartPtr m_msgHeader;
};
typedef
SmartPtr<FullStructuredMessage>
FullStructuredMessageSmartPtr;
|
之所以将FullStructuredMessage定义为抽象类,是为了强制要求应用层开发人员为每一个业务消息定义一个对应的完全结构化消息类型,即使某些业务消息没有消息体,也应该从FullStructuredMessage派生新类型并置空。
如何将一个具体的消息解析器注册到消息映射表中呢?显然,最好是将解析器对象直接放到消息映射表中对应消息ID的映射项内,而且仅需一个对象即可,所以最适合使用单例模式,这样就可以将对象的地址而不是对象本身放到消息映射表项中。具体细节参见本章2.10节。
例如,任一个具体的消息解析器定义如下:
|
class ExampleParser : public
FullStructuredMessageParser
{
DECLARE_STATIC_SINGLETON(ExampleParser) // like this!
public:
virtual
FullStructuredMessageSmartPtr \
Parse(HalfStructuredMessageSmartPtr pHalfMsg);
};
|
对应的全结构化消息应如下定义:
|
struct ExampleMessage : public
FullStructuredMessage
{
//
根据业务消息格式增加对应的数据成员,或为空
……
};
|
消息解析器的实现如下:
|
FullStructuredMessageSmartPtr \
ExampleParser::Parse(HalfStructuredMessageSmartPtr
pHalfMsg)
{
//
解析halfMsg的消息体
……
struct
ExampleMessage *pTemp = new ExampleMessage;
pTemp->m_msgHeader =
pHalfMsg->m_msgHeader; //
消息头直接赋值
pTemp->… =
…;
// 解析消息体并为其他成员赋值
return
FullStructuredMessageSmartPtr(pTemp);
}
|
加载中,请稍候......