模式名称
意图
动机
在网络通信软件的开发中, 经常要处理网络上接收到的各种数据报文. 而收到某种报文后, 需要进行的处理逻辑上可能不止一件事情. 处理过程中会用到报文中的数据, 因此需要对报文进行解析. 而报文的结构通常存在动态部分, 而在C语言中, 无法定义一个数据结构可以直接将报文映射到该结构. 参见<<Navigator Pattern: 导航者模式>>
缺乏考虑的做法通常会把解析和处理放在一起, 一个大函数, 用局部变量甚至全局变量来保存解析出来的数据, 并对其进行各种处理. 这样做的问题是:
另外一种常见的做法是每种不同的处理单独去解析自己需要的内容. 这种方式相对内聚, 但需要解析多遍报文结构, 解析代码也有重复
我们需要更好的设计.
方案
SAX以事件驱动的方式分离了XML文档的解析和处理. 我们可以借鉴. 报文有内部结构, 我们可以使用Navigator模式遍历其内部结构, 并在每一个独立的净荷开始和结束时触发回调, 而对报文内容的各种处理可以以回调函数的形式注册到解析过程中, 为每种处理编写单独的回调函数.
例如, 对于Navigator模式中定义的报文结构, 可以定义如下的API:
typedef void (*MessageHandler)(Message*); typedef void (*TopLevelPayloadHandler)(TopLevelPayload*); typedef void (*SecondLevelPayloadHandler)(SecondLevelPayload*); typedef struct Handler { MessageHandler start_handle_message; MessageHandler end_handle_message; TopLevelPayloadHandler start_handle_toplevel_payload; TopLevelPayloadHandler end_handle_toplevel_payload; SecondLevelPayloadHandler start_handle_secondlevel_payload; SecondLevelPayloadHandler end_handle_secondlevel_payload; } Handler; void parse(Message* message, Handler* handlers, int handler_count) { for(int i=0; i<handler_count; i++) { handlers[i]->start_handle_message(message); } //遍历Message内部嵌套的payload, 并调用对应的handler, 比如: //handlers[i]->start_handle_toplevel_payload(toplevel_payload_pointer); //handlers[i]->end_handle_toplevel_payload(toplevel_payload_pointer); for(int i=0; i<handler_count; i++) { handlers[i]->end_handle_message(message); } }
Handler handlers[3] = { DataPrinter, HardwareManipulator, DataPersister}; parse(message, handlers, sizeof(handlers)/sizeof(handlers[0]));
相关模式