北京英诺公司技术部 逄新利
---- 问题的提出
---- 我公司在开发医院信息管理系统的过程中,由于系统庞大,遇到这样一个棘手的问题: 我们制作了若干个用户自定义的数据窗口对象, 每个对象中封装了一个独立的功能, 如: 数据窗口排序功能,用户自定义列校验功能,下拉数据窗口快速录入功能,大文本录入功能,回车到下一列功能等等, 共12个功能对象, 由不同的人制作. 我们需要任意选取其中的某几个功能对象做为祖先继承, 由于PB不允许一个对象同时继承不同的祖先,且祖先一旦确定, 就不允许改变. 如果将这12个用户自定义数据窗口对象的功能全部封装到一个用户自定义数据窗口对象中, 虽然能解决继承问题, 但是该对象会很庞大,对象内部逻辑变得更复杂, 更难以维护,一些在调用时用不上的功能, 势必会在运行时消耗更多的系统资源. 既然继承的路走不通, 笔者就想出了一个对象变量引用的方法.
---- 解决问题的思路
---- 首先笔者引入了二个概念(指用户定义的数据窗口对象):
---- 1. 基本功能对象: 具有单一功能的,独立的,用户自定义的对象.
---- 2. 中间层对象: 把自己捕获到的事件以某种方式传递给基本功能对象实例变量, 以完成对基本功能对象相应的事件脚本的调用. 被继承, 但不继承任何其它对象.
---- 另做一个用户自定义数据窗口对象,它不继承任何对象, 称之为中间层对象, 在中间层对象中为每个需要用到的基本功能对象声明一个实例对象变量, 在中间层对象的事件中去调用实例对象相应的事件. 使用时继承中间层对象, 以完成对基本对象的选择与调用.(见图一)
---- 实现举例:
---- 1. 基本功能对象制作:
---- 新建二个数据窗口用户对象, 分别命名为: Uo_DwA, Uo_DwB . 在Uo_DwA 的Clicked 事件中写一行脚本:
---- MessageBox ( ' Uo_DwA ' , ' Uo_DwA 的单击事件')
---- 在Uo_DwB 的Clicked 事件中写一行脚本:
---- MessageBox ( ' Uo_DwB ' , ' Uo_DwB 的单击事件')
---- 2. 中间层对象制作:
---- 2.1新建一个数据窗口用户对象, 命名为 Uo_DwInterlayer .
---- 2.2为中间层对象声明二个实例变量:
---- GraphicObject Igo_BaseDwObject[] //每一个元素是一个基本对象的实例引用 Integer Ii_BaseDwObjectNumber //保存元素的个数.
---- 2.3. 加一个用来注册的对象函数, 用来注册基本功能对象. Uf_Register (GraphicObject a_obj[] , DataWindow adw_object)
---- 函数内容:
Long Ll_Circulater
Ii_BaseDwObjectNumber = UpperBound (A_Obj[])
FOR Ll_Circulater = 1 TO ii_basedwobjectnumber
Igo_BaseDwObject[Ll_Circulater] =
A_Obj[Ll_Circulater]
// 下行脚本用来注册基本功能对象中的实例变量
Idw_THIS (说明见下文)
//Igo_BaseDwObject[Ll_Circulater].Function
Dynamic Uf_RegisterDwo ( Adw_Object)
END FOR
Return
---- 2.4为中间层对象中加入每个基本功能对象拥有用户自定义事件, 在中间层对象的每个事件中加入如下脚本(事件Clicked):
Long Ll_Circulater
//调用被注册过的每个基本功能对象的相同的事件脚本
FOR Ll_Circulater = 1 TO Ii_BaseDwObjectNumber
//如果当前事件为EditChanged , 则把下行脚本中的
Clicked(xpos , ypos , row , dwo) 部分替换为
EditChanged(row,dwo,data)
Igo_BaseDwObject [Ll_Circulater].Event
Dynamic Trigger Clicked (xpos , ypos , row , dwo)
END FOR
Return
---- 3. 新建一个窗口, 命名为W_TestInterlayer . 在窗口中放置中间层对象: Uo_DwInterlayer . 默认控件名: Dw_1. 然后在控件Dw_1的Constructor 事件中对需要引用的基本功能对象进行注册, 即可实现引用基本功能对象的目的. 基本功能对象可以是任意个. 在Dw_1 的Constructor 事件中加入如下脚本:
//注册基础数据窗口对象
GraphicObject Lgo_BaseDwObject []
//声明一个可变长度的一维对象数组
//建立对象数组元素的实例, 以便对Uo_DwA进行引用
Lgo_BaseDwObject[1] = Create Uo_DwA
//建立对象数组元素的实例, 以便对Uo_DwB进行引用
Lgo_BaseDwObject[2] = Create Uo_DwB //
//用中间层函数注册对象数组和本数据窗口对象.
Uf_Register ( Lgo_BaseDwObject[] ,THIS)
Return
---- 4. 运行窗口W_TestInterlayer , 单击 DW_1 , 会依次弹出2个消息框.
---- 在实际应用中, 由于基本功能对象是被引用的而非继承, 所以基本功能对象脚本中的代词THIS为空, 为此:
---- 需要在基本功能对象中声明一个实例变量: DataWindow Idw_THIS .
---- 加一个注册函数用来为实例变量Idw_THIS 赋值. 函数名称 Uf_RegisterDwo (DataWindow , Adw_THIS) . 函数内容:
Idw_THIS = Adw_THIS
Return
---- 对象中所有对数据窗口操作的函数前都必须加上 “Idw_THIS.”, 进行完全路径的引用.
---- 因为这些基本功能对象被继承过,为了向前兼容, 所以要在它们的Constructor 事件中写入如下脚本:
IF Not IsValid (Idw_This) THEN
Idw_This = THIS
END IF
Retrun
---- 以便对实例变量Idw_THIS 自动赋值.
……