Posted on 2006-11-22 01:17
大大毛 阅读(357)
评论(0) 编辑 收藏 所属分类:
ASP
还是这份短工,虽然用的是ASP,不过俺在工作中还是有所收获。
以前就用ASP,用起来挺顺手的,当然是在代码量及逻辑的复杂度都比较小的时候感觉还挺好,呵。但是打这份工,接手的任务是修改一套系统的局部。系统的逻辑现在还挺乱的,不太容易理解,不过通过这段时间的研究还是学了不少。
这个ASP系统在结构上实现了一定的封装,功能页面全部使用 Function 来实现。每个ASP页面均由两部分组成,一个是外层文件(充当模板),另一个用Function来封逻辑,使用时在外层的ASP中使用 include 来引入逻辑页。同时整个系统的主干则按功能划分成了单独的功能模块,模块利用Function以及Class来实现,最后同样使用这种拼装的方式搭起一个系统的骨架。
这种架构看起来很不错,不过在今天俺写一张自用的ASP页面时发现了一些问题。
我的这张ASP是自己写自己用的,主要是用于探索库/表的结构以及发现数据特征。页面的功能除了提供 SQLServer的操作 外,另外还需要用于查看及分析从 AS400 上获取的数据。项目中与AS400的连接已经被封装成了组件,提取不同的数据需要通过组件向 AS400 主机发送不同的指令字符串来实现。由于指令字符串是根据一个协议来规范,因此合成不同的指令需要使用不同的逻辑。为了将这些复杂以及单独的逻辑加以进行区分,我想过利用现有系统的这种结构来完成,即每个指令的逻辑被放在一个单独的 Funtion 中,然后根据 页面 提交上来的参数来分别调用,结果程序变成这样 ( 这里使用的是示例代码 ):
程序原框架
Dim AS400Code
AS400Code = ""
AS400Code = Request("AS400Code")
'初始化"AS400连接组件"
Dim IQS
Set IQS = New IQS
'---------控制器------------
Dim CodeString,Head
Select Case AS400Code
Case "PSCA1000"
'调用指令封装逻辑
Call PSCA1000(CodeString,Head)
'调用 封装AS400连接 的组件
IQS.send(CodeString)
'显示连接组件持有的数据集
Call ShowRs(IQS.Rst,Head)
Case "PSCA1002"
'调用指令封装逻辑
Call PSCA1002(CodeString,Head)
'调用 封装AS400连接 的组件
IQS.send(CodeString)
'显示连接组件持有的数据集
Call ShowRs(Head)
Case Else
Response.Write "尚未支持AS400程式码:" & AS400Code
End Select
Set IQS = Nothing
'------------视图-------------
'显示功能帮助信息
Function ShowHelp()
Response.Write "<OL>参数AS400Code:AS400程式码:"
Response.Write "<LI>PSCA1000</LI>"
Response.Write "<LI>PSCA1002</LI>"
Response.Write "</OL>"
End Function
'使用二维表以及Head来生成 <table> 元素
Function ShowRs(Rst,Head)
'使用Rst来生成一个 <table> 元素,并利用 Head 来生成表头列
End Function
'---------AS400指令处理逻辑(模型)------------
Function PSCA1000(ByRef CodeString,ByRef Head)
'根据复杂的逻辑来合成CodeString以及数据报表头
End Function
Function PSCA1002(ByRef CodeString,ByRef Head)
'根据复杂的逻辑来合成CodeString以及数据报表头
End Function 这里提一下,就算是将 AS400指令处理逻辑 全部放在一个文件,并在当前的页面中使用 Include 包含进来,那么整个功能的框架也是没有什么变化的。
仔细看看这个框架,不难发现问题所在: 随着以后所支持AS400指令的增多,框架中充当“控制器”的 Select Case 部分将受到严重考验。
1.大量的Case分支充满其中,重复代码过多;
2.随着指令逻辑的增多,指令逻辑将不可避免的放入单独的文件中,这样一旦增加一个AS400指令就必须更改多个ASP页面;
3.页面为使用者显示一个功能帮助信息,其中需要显示到所能支持的指令以及指令含义信息,而这些信息又不可避免的需要在主页面中重复输入及更改。
累则思变 :-),想想例如JAVA/NET中的那些设计,如果能够利用上,把调用与实现分离就OK了。仔细分析一下上面的代码不难发现,问题出在“控制器”与“模型”的强耦合上,结果造成两者的“同步更新”。
降低耦合,最好使的方法就是在两者之间加入一个层 (接口) ,这样问题即可解决。由于ASP本身并不提供接口这一东东,只能自己来实现罗。下面是我的解决方法:
程序新的框架(分离的感觉真好)
'注意这里: --新增了一个 CodeDic 容器,它就是俺设计的接口
Dim CodeDic
Set CodeDic = Server.CreateObject("Scripting.Dictionary")
<!--#include file="As400Code.asp"-->
'-----------
Dim AS400Code
AS400Code = ""
AS400Code = Request("AS400Code")
'初始化"AS400连接组件"
Dim IQS
Set IQS = New IQS
'---------控制器------------
Dim CodeString,Head,myFun
If CodeDic.Exists(AS400Code) Then
Set myFun = GetRef(AS400Code)
Call myFun(CodeString,Head)
IQS.send(CodeString)
Call ShowRs(Head)
Else
Response.Write "尚未支持AS400程式码:" & AS400Code
End If
Set IQS = Nothing
'------------视图-------------
'显示功能帮助信息,看似代码增多了几行,不过俺再也不用改它了
Function ShowHelp()
Dim Code
Response.Write "<OL>参数AS400Code:AS400程式码:"
If CodeDic.Count < 1 Then
Response.Write "现在尚无指令支持"
Else
For Code In CodeDic
Response.Write "<LI>" & Code & ":" & CodeDic.Item(Code) & "</LI>"
Next
End If
Response.Write "</OL>"
End Function
'使用二维表以及Head来生成 <table> 元素
Function ShowRs(Rst,Head)
'使用Rst来生成一个 <table> 元素,并利用 Head 来生成表头列
End Function
'=========As400Code.asp=============
'---------AS400指令处理逻辑(模型)------------
'注意这里:由模型向接口注册
CodeDic.Add "PSCA1000","PSCA1000指令的说明信息"
Function PSCA1000(ByRef CodeString,ByRef Head)
'根据复杂的逻辑来合成CodeString以及数据报表头
End Function
CodeDic.Add "PSCA1002","PSCA1002指令的说明信息"
Function PSCA1002(ByRef CodeString,ByRef Head)
'根据复杂的逻辑来合成CodeString以及数据报表头
End Function 呵呵,就是这么简单。
中间层(接口):
这里我使用了一个容器来充当中间层,当然这里为了省事在容器的使用上并没有完全实现接口的功能。我这里向容器提交的 Key 是AS400指令处理函数名; Value 是外层页面上需要的对应帮助信息。如果想完全实现接口的话,应该这样用容器: key--功能名;value--处理函数名;这样一旦处理逻辑发生变动,只需更新对应的 value 即可。
模型:
这里有点变动,程序功能添加的控制权由原先的“控制器”转向“模型”,因为在这里它更容易变动一些。而且让它只与充当中间层的容器打交道。
视图:
同样的,也只让它与中间层打交道。
控制器:
这里变动最大,诸多不爽的 Select Case 分支被拿掉,控制器仅仅与中间层打交道。利用 VBScript 提供的 GetRef( funName ) 获取函数指针,来实现逻辑功能的动态调用。
每次需要新增AS400指令逻辑处理功能时,只需向As400Code.asp添加一个功能处理函数,并将其注册到容器即可实现整体功能的更新。
两个框架经过对比不难看出其优点,新的框架在新增功能时:
1.避免了重复的调用代码;
2.仅仅修改一处地方。