目 录
第七章 外部接口的设计... 2
7.1 插件接口... 2
7.2 图形显示接口... 3
7.3 数据导出接口... 5
7.4 服务组件接口... 6
7.5 插件管理器... 8
7.6 框架整合、重构... 9
7.7 小结... 10
开发者不仅可以二次开发设备驱动,还可以二次开发自定义图形显示形式、
自定义数据导出格式和多种业务服务,并且设备驱动接口与这三种接口进行事件响应和数据交互。
图形显示接口、数据导出接口和服务组件接口都继承自统一的插件接口(iplugins),主要是方便管理和扩展。插件接口的代码定义如下:
public interface IPlugins : IDisposable{ /// <summary> /// 服务Key,要求唯一 /// </summary> string ThisKey { get; } /// <summary> /// 服务名称 /// </summary> string ThisName { get; } /// <summary> /// 更新设备数据,用于接收来自设备驱动的数据信息 /// </summary> /// <param name="devid">设备ID</param> /// <param name="obj">设备对象</param> void UpdateDevice(int devid, object obj); /// <summary> /// 移除设备,当框架平台删除设备的时候进行响应。 /// </summary> /// <param name="devid">设备ID</param> void RemoveDevice(int devid);}
图形显示接口、数据导出接口和服务组件接口与插件接口的继承关系如下图:
设备驱动只要有更新数据就会通过事件把数据传送到UpdateDevice接口里,这个接口内部到底怎么处理完全由二次开发者来决定。当触发设备驱动的删除事件,就会调用RemoveDevice接口,以删除、释放资源。
框架平台通讯设备驱动把数据采集上来的只是原始数据,经过处理后要形成业务数据,那么就会有显示、分析、查询、打印、报表等业务功能,并且针对同样的数据信息,不同的用户要求处理的方式有很大的不同。这部分功能变动很大,但是又不能每次有变动就要去修改框架平台,因为框架是“稳定”的部分,形成版本控制后就不随便改变了。
基于这样考虑,作为框架要提供一个机制,能够加载二次开发者设计的UI窗体。用于显示采集终端设备的数据,可以把不同类型设备的数据以多种形式集成显示在不同界面上。方便为用户提供多种的、更友好的人机交互界面。
首先,框架平台不能在启动的时候就显示所有UI窗体,具体要显示哪个UI窗体完全由用户自己决定,所以,我们要通过配置文件的形式把二次开发的组件信息加载到菜单里,提供可触发的显示事件入口,如下图:
其次,那么以什么样的形式显示窗体呢?像很多管理系统一样,我们采用Form Tab的方式显示,如下图:
UI部分的设计就这样了,但是从业务角度我们要考虑两件事:(1)在二次开发的窗体上单击鼠标右键事件时要显示相应设备的上下文菜单,也就是说要调用IRunDevice设备驱动的ShowContextMenu函数,要在IGraphiCSShow接口中提供MouseRightContextMenuHandler事件,以驱动调用ShowContextMenu函数显示上下文菜单。(2)当单击菜单项的时候,会以Tab的形式显示窗体,但是当多次单击后是不能多次显示UI窗体的,所以要有一个管理器(GraphicsShowController),通过接口的ThisKey属性判断当前显示的UI窗体是否存在,如果不存在,那么就显示该UI窗体,否则退出操作;既然有一个管理器,当关闭窗体的时候,需要把该UI窗体实例从管理器中删除掉,避免无法再次显示窗体,因为它一直存在于管理器中。所以还需要在接口中定义一个关闭窗体的事件GraphicsShowClosedHandler,释放窗体资源后从管理器中删除实例。
至此,自定义窗体显示部分就设计完毕了,IGraphicsShow接口定义代码如下:
public interface IGraphicsShow : IPlugins{ /// <summary> /// 关闭窗体事件时发生 /// </summary> event GraphicsShowClosedHandler GraphicsShowClosedHandler; /// <summary> /// 单击右键 /// </summary> event MouseRightContextMenuHandler MouseRightContextMenuHandler;}
在数据集成系统项目中,要么是集成其他厂家的设备数据,要么是其他厂家集成自己家的设备数据,在没有统一的标准前提下,会有各种集成数据的格式。为了满足此类的场景,为设备导出数据专门设计了接口,开发者可以继承该接口,设备在处理完数据后,会把数据自动传输到该接口,可以按规定的数据格式进行输出了。
对设备驱动实时数据导出,可以把一类的设备数据导出成多种数据格式。
导出数据插件可以通过配置文件进行加载,只要设备驱动有数据更新,就把数据通过事件传递给导出数据接口。不在配置文件中配置插件信息,则程序不进行加载,不进行导出操作。所以,这种事务性的服务不需要界面来完成,可以在宿主程序启动时通过代码来完成。
IExportData数据导出接口代码定义如下:
public interface IExportData:IPlugins{ /// <summary> /// 格式化数据 /// </summary> /// <param name="devid"></param> /// <param name="obj"></param> /// <returns></returns> object FormatDataString(int devid, object obj, DeviceType devicetype);}
围绕着设备驱动模块采集的数据,根据应用场、需求,可以提供多种应用服务,例如:数据转发服务、4-20mA服务、短信服务、LED服务、OPC服务、以及复杂的实时数据分析服务等。在保障数据实时性、稳定性的前提下,服务接口可以提供统一的服务机制,方便开发者进行二次开发。
服务插件的服务方式,这种服务是长期运行的事务性任务,所以更复杂一些。
有些服务需要随宿主程序启动而自动运行,有些服务需要人工手动启动才运行。在宿主程序启动的时候通过配制文件要把服务的信息加载到菜单上,菜单里显示的服务可能有些已经启动了;有些需要通过单击操作,显示窗体并填写必要的信息后才可能启动。所以,宿主程序与服务插件不是单向交互,而是双向数据、事件交互。
IappService服务接口在IPlugins基础上进行扩展,增加了函数、属性和事件,代码定义如下:
public interface IAppService : IPlugins{ /// <summary> /// 启动服务 /// </summary> void StartService(); /// <summary> /// 是否自动启动 /// </summary> bool IsAutoStart { set; get; } /// <summary> /// 服务类型 /// </summary> ServiceType ServiceType { set; get; } /// <summary> /// 单击事件,关联菜单 /// </summary> void OnClick(); /// <summary> /// 释放服务 /// </summary> void ReleaseService(); /// <summary> /// 写日志事件 /// </summary> event WriteLogHandler WriteLogHandler;}
(1) StartService函数:当服务的启动方式(IsAutoStart)为"自动启动"的时候,框架平台在加载服务的时候,会自动调用这个接口函数,表示对服务进行启动操作。
(2) IsAutoStart属性:服务启动类型,标识是否随框架平台启动而自动启动,也就是标识是否会调用StartService接口函数。
(3) ServiceType属性:服务类型分为:显示模式和隐藏模式。显示模式的服务会在框架平台的菜单上加载以ThisName标识的服务名称;隐藏模式不会在框架平台的菜单中加载服务名称,可以把此类服务的IsAutoStart属性设置为自动启动,框架平台启动后自动启动服务。代码定义如下:
public enum ServiceType{ [EnumDescription("显示模式")] Show = 0x00, [EnumDescription("隐藏模式")] Hide = 0x01}
(4) OnClick事件函数:当服务类型ServiceType为“显示模式“的时候,服务名称会被加载到菜单中,当单击服务菜单项的时候,会调用相应服务的OnClick接口函数,可以在这个接口函数里调用窗体。
(5) ReleaseService函数:当关闭框架平台和人工手动停止服务后,可以通过这个函数释放服务资源。
另外,对于服务组件接口还涉及到服务状态,标识服务在运行的过程中处
于什么阶段,例如:服务正在启动、服务已经启动、服务正在运行、服务正在终止、服务已经终止等等。因为根据服务的事务复杂度不同,服务的状态也可能不同,所以服务状态的定义交给了二次开发者自己定义。
图形显示接口、数据导出接口和服务组件接口都分别有一个接口管理器,负责对各功能接口进行管理,它们都继承自IBaseManager<TKey, TValue>接口。继承关系图如下:
总的来说,框架平台涉及到四个主要的接口:IRunDevice设备驱动接口、IGraphicsShow图形显示接口、IExportData数据导出接口和IAppService服务组件接口。它们现在的继承结构关系如下图:
实际上继承这四个接口二次开发的模块都是以插件的形式加载到框架平台,框架平台在结构上实现了一整套的运行机制。对上面的继承关系结构图进行分析,还有整合、重构的余地,进一步明晰接口关系、整合代码,提高框架的可扩展性,计划重构后的接口继承关系如下图:
所有可扩展的接口都继承自一个插件接口,再分支出来其他的业务功能接口,类似于C#语言中所有实体都继承自Object一样。
框架内部实际上是对接口进行直接调用,接口与接口之间的配合又实现了一套协调机制,从而逐步实现了一个框架平台。作为接口实际上是实现了二次开发与框架平台对接的一种形式,并保证在框架平台的协调机制中实现特定的业务功能。所以,任何框架,从顶层来看都是对接口的设计。
作者:唯笑志在
mail:504547114@QQ.com
QQ:504547114
.NET开发技术联盟:54256083
文档下载:http://pan.baidu.com/s/1pJ7lZWf
官方网址:http://www.bmpj.net
新闻热点
疑难解答