2.1
宿主程序设计
插件式软件框架要有一个宿主程序来承载和加载插件,为插件、驱动提供可运行的环境,使宿主程序与插件无缝对接。宿主程序与插件是水和鱼的关系:有水无鱼,水就失去了价值;有鱼没水,鱼就会死去。从关系的角度来分析,开发框架的目的是与其他事物发生关系,包括插件、组件或其他软件。发生的关系越多、相处越融洽,证明这个框架的价值越高。
框架使用NET反射技术开发插件管理机制,本章不详细介绍具体的技术细节,在后面的章节再介绍其技术应用。
一个框架的宿主程序应该怎样设计呢?或是说从哪些方面去考虑设计问题?首先,这个问题不应该从技术角度去考虑,而应该从使用者的角度、二次开发者的角度来规划宿主程序。
从使用者的角度来分析,宿主程序应该包括用户管理、设备驱动管理、设备状态监视方式、自定义UI插件显示方式、自定义输出数据插件操作方式、服务插件的服务方式、软件运行的监视方式、串口IO通道监视方式、网络IO通道监视方式等。这些是从框架的方向进行规划,还需要再进一步细化,才能指导我们的开发工作。
用户管理要支持多用户及用户权限分配。针对实时数据采集框架,实际场景应用的时候,肯定会涉及两个角色:操作人员和工程师人员。针对操作人员的权限定位是可以查看参数和数据信息;针对工程师人员的权限定位是不仅可以查看参数和数据信息,还可以修改参数。
设备驱动(插件)是通过接口、抽象类设计的框架核心部分之一,可以把二次开发的设备驱动插件加载到框架中运行,完成数据采集、校验、解析、处理和命令下发等相关操作。同时,设备驱动还应该具备增加或删除相关设备插件的功能。增加设备插件的操作窗口如图2-1所示。
图2-1 增加设备插件
设备状态监视方式可以称为“设备运行器”,它并不是对不同类型设备驱动的参数、属性等数据进行简单显示,而是对设备通用参数、属性、实时状态等数据进行显示和监视,如设备ID、设备名称、地址、通讯类型、IO参数、IO状态、通讯状态、设备状态、报警状态、设备类型和设备编号等,如图2-2所示。
图2-2 设备状态
自定义UI插件显示方式的原理是,二次开发者在规范的接口的基础上开发数据显示方式,开发完成后将其挂载到框架的配置文件中,当用户单击某一个显示视图的时候,该视图会以标签页的形式显示,并且可以单击按钮进行关闭,如图2-3所示。
图2-3 自定义UI插件显示方式
自定义输出数据插件可以实时导出数据,可以把一类设备的数据输出为多种数据格式。输出数据插件可以通过配置文件进行加载,只要设备驱动有数据更新,就会把数据通过接口传递给输出数据插件,进行数据输出操作。不在配置文件中配置插件信息,则程序不进行加载和数据输出操作。这种事务性的服务不需要界面来完成,可以在宿主程序启动时通过代码来完成。
服务插件执行长期运行的事务性任务,有些服务需要随宿主程序启动而自动运行,有些服务需要手动启动才会运行。在宿主程序启动的时候要把服务的信息加载到菜单上,菜单里显示的服务有的可能已经启动,有些需要通过单击操作,显示窗体及填写必要的信息后才能启动。所以,宿主程序与服务插件不是单向交互,而是双向交互。例如,采集设备的数据并处理之后,要把数据上传到其他系统中,就可以开发一个服务插件来完成这项任务,如图2-4所示。
图2-4 服务插件
软件运行的监视可以监视框架运行情况和设备运行情况,把异常的信息友好地显示出来,并把异常的详细信息保存到日志文件,对于实时数据采集框架的运行很有帮助,如图2-5所示。
串口IO通道监视,指当某一个设备驱动以串口方式通信时,串口参数动态发生改变时,串口监视器会反映当前串口IO状态,如增加串口、删除串口、串口号和波特率的改变等,如图2-6所示。
图2-5 设备运行日志
图2-6 串口IO状态
IO状态监测需要对Socket实例的连接和断开进行事件反映,Socket实例有效时把信息增加到网络监视器中,Socket实例无效时,释放相关资源后,从网络监视器删除相关信息,如图2-7所示。
基于以上分析,我们需要构建一个完整的宿主程序,并使其具备必要的功能。宿主程序不一定很复杂,因为有些功能可以在设备插件中实现。构建的宿主程序如图2-8所示。
图2-7 网络IO状态
图2-8 宿主程序界面
仅有宿主程序还不够,还需要从二次开发者的角度分析宿主程序是否能够与二次开发者保持良好的关系。这里涉及宿主程序存在的形式问题。宿主程序是框架的一部分,希望二次开发者继承宿主程序后可以快速构建一个自己的主程序,在此基础上扩展功能,然后把宿主程序的关键控件的访问权限设置成protected。另外,宿主程序还需要一个配置文件,可配置二次开发者关心的参数,如标题、版本号、公司名称等。
经过上述解释,我们对宿主程序有了一个清晰的认识。界面的骨架已经搭建出来,在后期的开发过程序中从细节着手,可以逐步实现这些功能。但是,这样一个简单的界面需要很多类和模块的支撑,后面的章节会对模块进行详细说明。