按照笔者的构想,一个功能齐全的LIS系统,其软件体系结构应是下图这个样子的:
把体系结构做这样的划分,设计思想是:仪器接口框架主要完成对仪器原始数据的自动采集,并把采集到的原始数据交给插件(业务逻辑层),插件则根据仪器的接口说明书,提炼出各检验项目的正确结果后,传回接口框架,由框架把结果保存至HIS数据库。此设计思想的核心是:利用插件(plug-ins)机制建立可扩展的解决方案,把业务逻辑接口暴露给用户(各医院的信息专家),由用户来完成业务逻辑层的编写(当然很简单,就是把框架丢过来的字符串,按一定的规则截取相应位置上的子串而己),并把业务逻辑层编译为插件,插入框架中后,一个完整的接口应用程序就可付诸实用了。
按照这种构想,框架是不用关心插件是如何完成对数据的解析的,插件也不用管框架是如何完成对串口的读写的,不用管解析后的项目结果,框架是如何处理的。二者只要严格按照业务逻辑接口层的协定进行通信,就可实现我们的设计。
二者如何进行通信呢?这里我们采用C#和.NET作为开发平台,具体阐述一下实现的步骤:
首先,建立接口(定义在业务逻辑接口层):
在C#程序中,接口是用来定义一个类的功能的.接口定义了预期的方法,属性,事件信息.为了使用接口,每个实现接口的类必须严格按照接口的定义完成所描述的功能。我把这个接口定义为:IPlug.这个接口定义了以下成员:
void ParsingData(byte[] data):该方法用于解析框架丢过来的原始数据;
event DataReadiedEventHandler DataReadied:每解析好一个项目结果后触发此事件,通知框架显示。
event DeleteOldDataEventHandler DeleteOldData:每收到新样本数据时触发此事件,通知框架删除数据库中的老数据。
event EventHandler InsertToDB:每样本的数据全部解析完成后触发此事件,通知框架把数据保存至数据库。
其次:定制属性 (定义在业务逻辑接口层)
自定义属性(atrribute)的作用是用来描述插件的信息的,它可以定义自描述的元数据,比如说插件名称,插件用途等(当然,你作为插件的开发者,可以把你的大名,甚至版权信息写进去了^-^)。这里,我定义了两个定制的属性:PlugDisplayNameAttribute和PlugDescrīptionAttribute,所有的插件内部的类必须支持这两个属性。在程序运行的时候,主程序将可以利用反射(reflection)来取得属性值.
三、编写插件(Plug-Ins)(定义在业务逻辑层)
插件的编写由用户来完成(当然不可能由我来完成啦,我怎么会知道你们医院用的是什么仪器、其输出格式是什么样子的呢?),插件随你怎么写,但必须有如下约束:
1.必须实现了IPlug接口。由于框架根本不会知道插件内部的类是如何定义的,这非常重要,框架需要使用IPlug接口和各个插件通信。
2.必须被上述两个属性标识,这样使用者才知道这个插件是谁写的、用于什么仪器的呀:)
四、加载插件
在一个插件定义好之后,下一步要做的就是看看框架是怎么加载插件的.为了实现这个目标,框架使用了反射机制。反射是.NET中用于运行时查看类型信息的。在反射机制的帮助下,类型信息将被加载和查看。这样就可以通过检查这个类型以判断插件是否有效,如果类型通过了检查,那么插件就可以被实例化,接口的成员就可以被框架调用。
OK,至此整个设计构想完成。或许有人要大呼上当:原来你的框架只不过是个半成品!需要用户自己来完成插件的编写工作,才能部署使用。是的,框架本来就是某种应用的半成品,就是一组组件,供你选用完成你自己的系统。简单说就是使用别人搭好的舞台,你来做表演。如果你连编个插件都赖得做,那就没得办法了,因为世上根本就不存在这种真正“包罗万器”的软件。如果我们把接口框架比作一个有牢固地基和框架的建筑,而各个房间就是没有装修的“插件”,房产商交付房子后,用户岂不应该自己装修,以满足不同的功能需求耶?下图是框架完成后的运行界面:
LIS是一个非常复杂的系统,本文仅阐述了笔者关于开发联机接口框架的构想,由于篇幅限制,其中的许多核心问题如检验报告的处理、质控管理等内容不能在此论述,我会在以后的文章中发表。欢迎大家多提宝贵意见!