表格驱动编程在代码中的应用
1. 毕业设计中的使用
第一次使用表格驱动编程,是在大学毕业设计的时候。做一个LL(1)的词法分析程序,需要读取终结符、非终结符、以及推导公式。程序会根据以上信息生成FIRST集合和LAST集合,然后根据递归下降分析的方法,就可以判断当前的表达式,是否符合对应的文法规则了。因为在代码中对于推导用到的表格没有写为Hard Code(写死,硬编码),所以可以适应很多的符合规则的文法。
2. 开源代码中的使用
第二次遇到表格驱动编程的方法,是在LXGJ,做jpg图像的压缩,用的是jpeg2000。当时还写了一篇文章,总结了一下,具体见 https://www.geek-share.com/detail/2617464380.html 。这里的代码采用的是动态生成表格的方式,在函数中通过宏来控制表格的大小,来实现动态的支持不同图片格式的解析。
3. 工作中使用
在LXGJ的时候,领导布置了一个任务,需要用户选择从不同的来源生成PDF,大致有扫描、文件、图片……,需要做成一个类似于Eclipse(Visual Studio)生成工程的向导类似的。然后明白了需求以后,我就开始写代码了。然后项目经理过来问我做的怎么样了,我把写了好多 if else的代码拿给他看,他说“你怎么能这么写呢,万一需求有变化,怎么改。
代码类似于
if( SCAN == type ) { dlg = new ScanDialog(); dlg.show(); if(DPI300 == dlg.getDpi()) { ..... } } else if(FILE == type) { ... } else if(IMAGE == type) { .... }
以上的代码在遇到规则有变化,或者每一步方式的选项要增加或者减少的时候,修改比较麻烦。
项目经理的建议
Dialog choiceDialog[4][5]= { new ScanDialog(),new DpiDialog(),new xxDialog(),NULL, new FileDialog(),new xxDialog(),NULL,NULL, new ImageDialog(),new DpiDialog(),new ImageTypeDialog(),new xxDialog(),NULL, NULL,NULL,NULL,NULL,NULL, }
采用下面的这种写法具有更好的可扩展性和灵活性。如果需要增加一种方式,则可以增加一行,如果需要增加方式中的一个选项,则可以在某行的某列后面增加一个dialog,用NULL表示结束,可以每种方式经过的选项不同。
4.我的新发现
在LXSJ的时候,我们需要对APP登录做验证,验证的过程比较多而且规则有可能会变化。这个时候采用表格驱动编程是一种很好的方式。举例说明如下:
比如我们需要验证
1、用户是否余额--->有余额允许登录,没有不允许;
2、用户是否是VIP会员--->是会员允许登录,不管其他条件;
3、用户如果是合作方的用户--->则合作方决定是否允许登录;
4、用户如果已经是老用户--->是允许登录,不是不允许登录;
此时可以采用老办法,用if else来写。但是新的方法是采用表格驱动,具体如下。
表格的每一项对应一个判断函数,返回 bool 值。
loginLogicTable[][] = { /*当前需要进行的判断,成功时的状态,失败时的状态*/ LOGIN_START,IS_VIP,IS_VIP, IS_VIP,LOGIN_SUCCEED,HAS_BALANCE, HAS_BALANCE,LOGIN_SUCCEED,IS_REGULAR_CUSTOMER, IS_REGULAR_CUSTOMER,LOGIN_SUCEED,IS_PARTER_CUSTOMER, IS_PARTER_CUSTOMER,SEND_REQUEST_TO_PARTER,LOGIN_FAILED, RECIVE_PARTER_RESPONSE,LOGIN_SUCCEED,LOGIN_FAILED, }
以上是此时规则的描述,其中 LOGIN_SUCCEED 与 LOGIN_FAILED 是最终的状态。
第一项对应着一个函数,使用这个表格的伪代码如下
bool isLoginSucceed(userInfo) { curState = LOGIN_START; while( curState != LOGIN_SUCCEED && curState != LOGIN_FAILED) { changeArray = findArray(curState); //返回loginLoginTable中的一行 if(callFunc(changeArray[0]) { curState=changeArray[1]; } else { curState = changeArray[2]; } } return curState == LOGIN_SUCCEED; }
如果不需要判断是否是合作伙伴的用户了。
则将
IS_REGULAR_CUSTOMER,LOGIN_SUCEED,[IS_PARTER_CUSTOMER], //改为 IS_REGULAR_CUSTOMER,LOGIN_SUCEED,[LOGIN_FAILED],
就可以了,改动非常的方便。
如果要增加一个判断,比如要增加xyz指令判断。
则修改如下:
IS_REGULAR_CUSTOMER,[LOGIN_SUCEED],IS_PARTER_CUSTOMER, IS_PARTER_CUSTOMER,SEND_REQUEST_TO_PARTER,LOGIN_FAILED, RECIVE_PARTER_RESPONSE,LOGIN_SUCCEED,LOGIN_FAILED, /*改为*/ IS_REGULAR_CUSTOMER,[JUDGE_XYZ_CMD],IS_PARTER_CUSTOMER, IS_PARTER_CUSTOMER,SEND_REQUEST_TO_PARTER,LOGIN_FAILED, RECIVE_PARTER_RESPONSE,[JUDGE_XYZ_CMD],LOGIN_FAILED, [JUDGE_XYZ_CMD],LOGIN_SUCCEED,LOGIN_FAILED,
可以看出,此时的修改很小,而且逻辑很清楚。
- 驱动里执行应用层代码之KeUserModeCallBack(WOW64是由三个动态库wow64.dll wow64win.dll wow64cpu.dll来实现)
- 12.队列的应用-事件驱动编程
- 配置----Hibernate可配置的编程方式,驱动、URL、数据库访问岁用户名、密码等用使用Java代码手动加载!
- .Net AJAX表格控件-不写一行代码就能做复杂AJAX应用
- .Net AJAX表格控件-不写一行代码就能做复杂AJAX应用
- 第一章:iOS应用安全概要——1.1.6 事件驱动模型、编程和应用
- SAP ABAP编程 维护视图(表格维护生成器)创建事务代码
- 基于visual c++之windows核心编程代码分析(62)读取本地已登录的QQ号及应用代码
- android内核字符驱动设备实战之----------运行时库层jni动态库编程(应该是应用框架层)
- c# winform 应用编程代码总结 12
- c# winform 应用编程代码总结 15
- 基于visual c++之windows核心编程代码分析(62)读取本地已登录的QQ号及应用代码
- linux 驱动学习笔记02--应用实例:在内核中新增驱动代码目录和子目录
- c# winform 应用编程代码总结 7
- 基于visual c++之windows核心编程代码分析(62)读取本地已登录的QQ号及应用代码
- Linux 音频设备驱动架构及应用编程
- 事件驱动编程---队列应用--银行排队模拟--学习与思考
- Linux 音频设备驱动架构及应用编程
- 最全的表格代码应用
- c# winform 应用编程代码总结 4