摘要:本文介绍了信息系统软件开发中如何满足需求多变的情况。通过对软件系统提供二次开发能力,可以灵活扩展、定制系统功能,满足实际应用需求的变化。
关键字:二次开发,组件对象模型,动态加载
0.概述
在一些通用性质的软件系统设计中,由于实际应用中需求的多样性和多变性,需要充分考虑软件系统功能的高度定制性、可修改性等问题。由于市场行情的变化,杭钢炼铁厂由原来产量优先生产转变为成本优先生产。由于追求的首要目标的转变,对生产信息管理系统提出了更多新需求,软件系统需要为满足这些新要求不断更新设计,扩展功能,随着系统不断扩充,复杂性也越来越大,维护也变得更为困难,因此有必要通过提供二次开发能力这种方式,变更软件系统框架,使软件应用具有更强灵活性。
本文介绍在开发生产管理信息系统中扩展二次开发能力的方法。
1.实现形式和方法
1、范围界定。首先需要定义系统中允许二次开发的功能范围。生产管理信息系统包括两部分:数据采集和数据库信息系统。数据采集系统主要针对用于定义的实时采集信息的变量,允许针对特殊类型的标签变量根据特定的计算公式编写代码;根据标签变量实时采集值实现相关特殊的操作如数据库访问等等。数据库信息系统则允许根据实际需求增加、修改、删除生产管理相关的功能。均采用动态加载外挂自定义模块的方式实现。
2、自定义功能模块。为了将新的功能融合进已有系统之中,可以将生成为dll模块或者可独立加载的exe模块通过动态加载的方式载入内存并可以根据需要从内存动态卸载。可以使用普通的动态链接库,或者COM组件技术设计。这些自定义模块称为外挂模块,提供的扩展功能接口称为外挂接口。
1)COM组件技术,COM(组件对象模型)是由微软定义的软件组件之间的通讯标准。组件动态加载和卸载。编译后的COM组件可以是动态链接库dll文件(进程内组件),也可以是可执行的exe文件(进程外组件),两者在稳定性和执行效率方面差异很大,需要仔细权衡。
2)普通的动态链接库dll函数。dll模块预先加载到内存。Dll的动态加载和卸载可以使用LoadLibrary和FreeLibrary函数。
在系统启动时,完成用于自定义库函数的加载,并完成配置的函数名与函数地址的转换。
在具体的实现中,采取将用户的每个配置信息中均包含一个函数类型的变量,以及一个字符串变量。字符串变量包含所引用的函数名称以及所在模块,函数类型变量则用于指向所需要调用的函数地址,这个函数地址可以在系统启动时初始化。
由于COM是基于对象概念的,需要考虑的比普通dll模块较复杂一些。加载时需要首先创建COM对象的实例,然后通过对象的接口才能访问到需要的函数。考虑到软件系统是否多线程的,对COM组件对象的创建和使用会有所不同,COM组件模型的设计需要和系统匹配。
COM组件外挂接口的调用的主要是通过IDisptach接口的invoke方法实现。
2.开发语言及编译器的选择和处理
无论是使用com组件还是普通dll函数库,也无论是嵌入式开发环境加自动处理或者是单独开发,系统都需对新代码的编译、链接所需要的环境参数进行配置,以便可以生成所需要的外挂函数库。选择支持的开发语言不同,配置也会有变化。对于灵活定义标签变量取值这种类型,可以直接内置一个dll工程,并在标签变量编辑界面提供公式编辑,保存时为每个自定义标签变量对应的代码自动生成一个对应的函数,并自动完成编译和链接。由于函数库是动态加载的,因此可以对原标签变量库进行在线编辑修改。
语言的选择问题。可以选择已有的通用型高级编程语言,如Visual Basic/C#或者c/c++等等;也可以针对系统特点专门设计一套简易语言系统。本系统选择了vc和vb开发、编译环境。
从易用性上来说,Visual Basic语言是比较好的选择,编译和链接直接使用vb的编译功能,生成需要的代码库。使用vb则编写com组件,是相当简单的(此时外挂文件可以是dll或者exe两种形式)。但实现普通的windows dll函数库则是一个比较麻烦的事情。
c和c++不单代码效率高,而且可以满足更复杂的要求(比如多线程机制)。因此某些情况下选择使用vc的编译和链接器,当然也可以选择其它更高效的编译工具。
对于某些稳定性要求比较高的系统,可以专门设计一套针对性的高级语言,类似于SQL数据库查询语言,仅提供可靠的数据类型、操作和控制。但需要对这套语言开发一套语言翻译器,首先将源代码翻译为c/c++或者其它可用的成熟的编译系统的语言,然后再使用相关的编译器进行处理。
3.外挂接口模块访问信息系统软件内部资源
信息系统系统需要提供一些接口,供外挂接口模块调用,用于访问系统核心的功能和数据。这些内部接口定义已经包含在环境设置之中,不需要再单独显式声明。
要使外挂模块中的代码能够访问系统主体程序中的接口、资源,可以使用回调函数机制实现;也可以将主体系统接口导出,提供lib库文件的方式;或者将包含这些接口的系统核心功能设计为独立加载的dll函数库模块,而是否再单独提供lib库文件可根据具体实现决定。不管怎样,这些对系统的二次开发过程应当是透明的,只需按照约定直接调用即可。本系统的设计采用了第二种方法。至于各外挂模块之间的功能调用,可以参考上述第三种方式实现。
4.稳定性和效率的考虑
灵活性和稳定性是一把双刃剑。除了对源代码做出一些必要限制外,从系统的设计上也需要做充分的考虑以最大限度的提高稳定性,防止因外挂模块的问题使整个系统受影响,比如效率降低甚至崩溃。如对于实时数据采集系统,涉及到的网络访问、文件操作等必需通过调用信息系统内部接口来完成。
对于模块的实现方式,使用COM进程外组件的方式稳定性会较有保障,但性能会很差;COM进程内组件以及普通dll模块则容易使主程序直接崩溃,但性能高。无论是使用哪种方式,系统主程序都需要对由于用户自定义代码可能引起的异常作充分考虑以使整个系统更加健壮。
4.结束语
通过对软件系统实现可编程性,使其可以在原来的基础上进行二次开发,增加软件系统的通用性以及可扩展能力。尤其可以对软件系统的原有功能进行裁减、修补,以实现更好的适应新的需求。这种实现方式也使系统框架清晰明确,易于维护。
这篇文章写了已经差不多快5年了,在现今B/S架构越来越有取代一切的趋势下,在回首看看这篇文章,我觉得很有意义。B/S架构的真正意义是什么?我觉得就是成本。而要实现复杂的前端应用,还必须要使用桌面级应用系统。B/S的势头已经有点过了。但愿我不是老学究,守旧派。谨以此纪念曾经的岁月。