模式名称
- Navigator/导航者, 一种通信软件报文处理模式
意图
- 封装报文数据复杂的内部结构, 通过提供有业务含义的寻址操作来避免危险的指针运算, 以减少重复和出错的可能, 并提供更清晰的业务意义
动机
在网络通信软件的开发中, 为了传输效率或完整性的考虑, 通常在应用层协议的定义中, 一次可以发送多个单位的净荷数据, 其具体数量可用报文头中的某个字段来描述. 另外一些时候报文体的长度是不定的, 通常也用报文头中的某个字段来表示实际的报文多长.
而此类软件通常以C语言开发完成. 经典的实现方案是为报文定义如下的数据结构, 并以指针运算来寻址特定的数据. 而当数据结构有嵌套时, 其指针运算将变的异常复杂和易错:
typedef struct SecondLevelPayload {
int field_1,
char field_2,
float field_3
} SecondLevelPayload;
typedef struct TopLevelPayload {
int some_top_level_field,
int second_level_payload_count,
SecondLevelPayload* payload //payload之间有嵌套
} TopLevelPayload;
typedef struct Message {
int count,
TopLevelPayload* payload
} Message;
void print_datagram(Message* message) {
TopLevelPayload* current = message->payload;
for(int i = 0; i < message->count; i++) {
PrintTopLevelPayload(current++);
//or PrintTopLevelPayload(message->payload[i]);
}
}
上面最后的函数试图循环打印所有TopLevelPayload, 但寻址方式却是错的, 因为第二个TopLevelPayload的地址并不是第一个的地址加上其自身结构体的长度. 这里的症结在于C语言缺乏描述动态集合的设施, 只有指向首地址的指针, 而指针的大小和其指向的数据的大小是不同的. 又因为数据流是连续的, 因此据此定义的结构体的大小和实际数据的大小是不一致的. 初步的改正如下:
void print_datagram(Message* message) {
TopLevelPayload* current = message->payload;
for(int i = 0; i < message->count; i++) {
PrintTopLevelPayload(current);
current = (TopLevelPayload*)((char*)current + sizeof(TopLevelPayload) + current->second_level_payload_count * sizeof(SecondLevelPayload));
}
}
这样代码就变得晦涩, 看不出意图. 而指针运算容易出错, 且当其它代码需要在报文内部寻址的时候需要重复一遍代码来再算一次, 当报文协议/结构体定义变化的时候, 需要检查所有现存的指针运算看是否还合适. 我们需要更好的设计.
方案
这里的问题是寻址. 而现实生活中, 当我们需要去某个地址的时候, 我们借助导航. 它可以是一部仪器, 也可以是熟悉当地环境的路人. 但接口是一致的: 我们只需要告诉他我们要去哪, 不需要提前了解地形. 在C语言中, 它可以是围绕着报文首地址指针提供的一组有业务含义的接口函数:
TopLevelPayload* goto_nth_toplevel_payload(Message* message, int nth_toplevel_payload) {
TopLevelPayload* addr = message->payload;
for(int i = 0; i < nth_toplevel_payload; i++) {
addr = (TopLevelPayload*)((char*)addr + sizeof_toplevel_payload(addr));
}
return addr;
}
SecondLevelPayload* goto_nth_secondlevel_payload(TopLevelPayload* top, int nth_secondlevel_payload) {
return top->payload + nth_secondlevel_payload;
}
static int sizeof_toplevel_payload(TopLevelPayload* payload) {
return sizeof(TopLevelPayload) + payload->second_level_payload_count * sizeof(SecondLevelPayload);
}
这样, 通过报文首地址和goto_nth_toplevel_payload(), goto_nth_secondlevel_payload()两个函数, 客户代码就可以在报文体中任意巡航, 而无需理会其内部表示, 无需涉及易错和晦涩的指针运算. 当报文协议变化时, 我们也只需要修改navigator, 无需修改客户代码.
相关模式
Page Object模式描述了在web应用测试领域针对易变的web页面进行封装的方法, 其中也涉及对页面不同元素的导航. 其解决的主要问题是减少相对频繁的页面变化对测试代码的稳定性造成的冲击, 并更清晰的描述测试意图.
分享到:
相关推荐
DOM导航器允许键盘浏览DOM元素(←↑→↓)的库。安装凉亭bower install dom-navigator --saveNPM npm install dom-navigator --save手册。 然后将dom-navigator-###.min.js到您HTML页面中。用法纯JavaScript var el...
总结来说,"navigator:网络导航工具"涉及了Web开发中的重要概念,包括JavaScript的Navigator对象和HTML的基础知识。了解和熟练运用这些知识对于构建高效、兼容的网页应用至关重要。通过深入研究"navigator-main"这样...
Cloudera Navigator SDK是一个客户端库,它提供的功能可帮助用户从Navigator中提取元数据,并使用自定义元数据模型,实体和关系丰富Navigator中的元数据。 样例用例 增量元数据提取 某些应用程序需要出于自身目的从...
可用脚本在项目目录中,可以运行:yarn start 在开发模式下运行应用程序。 打开在浏览器中查看它。 如果您进行编辑,则页面将重新加载。 您还将在控制台中看到任何棉绒错误。yarn test 在交互式监视模式下启动测试...
Navigator具有精致的业务和公司元素,并拥有丰富的版式,它是轻量级的,快速加载,响应Swift且经过W3C验证的,给访问者留下了深刻的第一印象。 基于Bootstrap 4的导航器,并提供了惊人的设计布局。 这些图像仅用于...
《LJ-Navigator基恩士项目实例使用方案》是一篇关于如何使用特定软件和设备进行2D扫描仪操作,以及如何将读取的数据记录到数据库中的技术文档。通过这篇文档,我们可以学习到一系列有关于自动化检测、数据记录和程序...
Navigator是React Native早期的一个核心导航组件,用于管理应用中的路由和屏幕切换。在React Native 0.44版本中,Navigator仍然被广泛使用,但请注意,这个版本相对较旧,随着时间的发展,React Native已经推出了...
DBNavigator是Delphi等RAD Studio开发环境下常用的一个数据导航控件,用于在界面上提供数据记录的浏览、添加、删除等功能。默认情况下,DBNavigator是以水平方式排列其子控件(如按钮)的。但在某些应用场景下,为了...
GPS导航系统是全球定位系统(Global Positioning System)的简称,是一种基于卫星定位技术的全球性的定位、导航和定时服务系统。它通过接收多颗卫星发射的信号,计算出接收设备的位置、速度和时间信息。在本压缩包...
《WinCC技术手册——WinCC/WebNavigator 使用入门》是一份专为中文用户设计的详细指南,旨在帮助读者理解和掌握Siemens的WinCC监控与控制系统以及WebNavigator模块的使用方法。WinCC是西门子推出的一款强大的人机...
【brackets-navigator:将导航器放在括号中以显示代码结构】 在编程环境中,代码结构的清晰理解和快速导航是提高开发效率的关键因素之一。"brackets-navigator" 是一个针对JavaScript开发工具Brackets的扩展插件,它...
evil-tmux-navigator将这两个工具的功能紧密结合,使得在Emacs内使用evil模式时,可以通过相同的快捷键在tmux窗口和split之间导航。例如,通常在tmux中,你可以使用`Ctrl+b`然后按`h`, `j`, `k`, `l`来在左右和上下...
2. **组件使用**:WXML中的`navigator`组件用于创建导航链接,可以学习如何设置跳转路径,以及添加自定义事件。 3. **样式控制**:通过分析WXSS文件,理解如何使用CSS样式来实现固定定位,以及与其他元素的相对布局...
Navigator.nvim :sparkles: 在拆分和窗格之间平滑导航 :sparkles: 要求 Neovim每晚(0.5) 安装 使用 use { ' numToStr/Navigator.nvim ' , config = function () require ( ' Navigator ' ). setup () end } ...
用户可以通过命令行输入配置指令,实现对设备参数的设置,如时隙分配、保护模式选择等。 2. 故障排查:当网络出现问题时,Navigator能提供详细的告警信息,帮助工程师快速定位故障源。同时,其诊断工具可以进行环回...
"Laravel开发-navigator"是与Laravel框架相关的扩展,它是一个框架无关的导航包,专门设计来处理Web应用中的导航条目的活动状态和访问权限。 Navigator包的核心功能在于动态管理导航项的激活状态,这在多页面应用...
《OptiX Navigator 6.2:深入了解华为传输网管系统》 OptiX Navigator 6.2是一款由华为公司推出的高效能传输网络管理系统,它主要用于监控、管理和维护华为的光传输网络设备,如SDH(同步数字体系)、WDM(波分复用...
在顶部可能会有一个`view`或`navigator`组件,用于展示导航栏,并设置相应的样式使其固定在屏幕顶部。 - **wxss**:`.wxss`是样式表文件,用来控制页面的样式。开发者会在其中设置固定定位(`position: fixed`)、...
Compass Navigator Pro 2 v1.9Unity指南针导航仪 Pro 2 支持Unity版本2021.3.16或更高 终极UI导航系统,包括指南针栏、战争迷雾迷你地图、雷达模式、屏幕指示器、信标效果、全屏滚动地图等。 描述 Compass Navigator...
**Source Navigator(Windows版)** Source Navigator是一款广受赞誉的开源软件,专为Windows平台设计,用于高效地浏览和分析源代码。它以其强大的功能和直观的用户界面,被誉为最佳的源代码查看工具,能够帮助开发者...