打印
[ZLG-ARM]

可动态扩展多分支选项的实现(转)

[复制链接]
1248|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
3B1105|  楼主 | 2011-12-28 17:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

1.1.1
利用查表调用函数通过之前介绍的范例可以看出,“打印的帮助信息”同样也不能做到动态绑定,同时还需要用手工添加case语句及处理函数。可想而知其扩展性很差,这是开发过程中最容易被忽略的问题。

1.   高级声明
或许,上面的示例都过于简单,下面不妨来一点刺激的。我们可以先声明一个结构体类型,并同时定义一个结构体变量,然后再定义一个结构体数组,其示例如下:
1       #define HELP_LEN 64                                // 函数说明的最大长度
2       #define TABLE_LEN 10                               // 函数表中的最大的函数个数
3
4       typedef struct CmdEntry{
5               void (*pfuncmd)();                         // 定义函数指针,用于接收函数的入口地址
6               char cHelp[HELP_LEN];
7       }CmdEntry;
8      
9       static CmdEntry cmdArray[TABLE_LEN] = {           // 定义结构体数组(函数表)并初始化
10            {&CreateFile, "新建文件"},                  // CreatFile()函数地址,帮助信息
11            {&OpenFile, "打开文件"},                    // OpenFile()函数地址,帮助信息
12            {&SaveFile, "保存文件"},                    // SaveFile()函数地址,帮助信息
13            // <标注1>在这里添加函数
14            {0, 0}                                      // 退出
15     };
     注意:在这里定义数组的长度是为了方便下一个版本添加调用函数。

    2.   利用查表调用函数
     根据上面的定义,即可用以下方式获得函数的入口地址。

         cmdArray[iCmdNum].pfuncmd
然后用函数指针回调相应的功能函数,其示例如下:
         cmdArray[iCmdNum].pfuncmd();
由此可见,如果采用回调函数法,且以动态绑定的方式,则程序的可扩展性得到了很大的提升,因为我们只需在“<标注> 1处注册自定义的函数,无需多处修改代码,不仅可以很好地解决程序的可扩展性问题,而且还大大地降低程序的出错几率,详见程序清单1.1
程序清单1.1  控制台菜单选项程序(V0.5
1       #include <stdio.h>
2       #include <stdlib.h>
3
4       #define HELP_LEN 64                            // 函数说明的最大长度
5       #define TABLE_LEN 10                           // 函数表中最大的函数个数
6
7       typedef struct CmdEntry{                       // 定义函数结构体
8               void (*pfuncmd)();                     // 接收函数入口地址的函数指针
9               char cHelp[HELP_LEN];
10     }CmdEntry;
11
12     void ShowHelp();
13
14     // 此处省略CreateFile()函数代码                 // “新建文件”菜单
15     // 此处省略OpenFile()函数代码                   // “打开文件”菜单
16     // 此处省略SaveFile()函数代码                   // “保存文件”菜单
17
18     static CmdEntry cmdArray[TABLE_LEN] = {         // 定义函数表
19           {&CreateFile, "新建文件"},
20           {&OpenFile, "打开文件"},
21           {&SaveFile, "保存文件"},
22           // <标注1>在这里添加函数
23           {0, 0}
24     };
25
26     void ShowHelp()                                // 显示函数表中的内容
27     {
28         int i;
29
30         for (i = 0; (i < TABLE_LEN) && cmdArray.pfuncmd; i++) {
31                 printf("%d\t%s\n", i, cmdArray.cHelp);
32         }
33     }
34
35     void CmdRunning()
36     {
37         int iCmdNum;
38            
39         while (1){
40               ShowHelp();                  // “帮助信息”显示初始化
41               printf("请选择!\n");
42               iCmdNum = getchar() - '0';  // 将字符转换为数字,转换失败也可以
43               fflush(stdin);              // 清空缓冲区
44               if (iCmdNum >= 0 && iCmdNum < TABLE_LEN && cmdArray[iCmdNum].pfunCmd){
45                      cmdArray[iCmdNum].pfunCmd();
46               }
47               else{
48                        printf("对不起,你选择的数字不存在,请重新选择!\n");
49               }
50          }
51     }
52     void main()
53     {
54         CmdRunning();
55     }
这种方式相对来说其扩展性有了很大的提升,只需要在“<标注1>”处注册自定义的函数即可,帮助显示函数ShowHelp()会自动地显示新增加的函数帮助信息,因为修改一处比修改多处出错的可能性要低得多。
1.1.2    提供通用接口如果采用上述方式注册函数,则必须在这个文件的“<标注1>”处修改源代码。很多时候,当需要扩展菜单功能时,而又不允许随意修改源码,怎么办?唯一的解决方法就是为系统增加一个可动态扩展的接口函数,详见程序清单1.2
程序清单1.2  动态扩展接口函数(V0.6
1       void AddCmd(CmdEntry cmdentry)
2       {
3                int i;
4
5                for (i = 0; (i < TABLE_LEN) && cmdArray.pfuncmd; i++) {
6                          ;                          // 找到空的功能条目位置
7                }
8                if (TABLE_LEN == i) {
9                          printf("Sorrytable is full!");
10              }
11              else {
12                        cmdArray = cmdentry;
13              }
14     }
当以后需要扩展菜单项时那么只需要调用AddCmd接口即可。不过这里还是有一个不足之处,当菜单项的数量达到定义的TABLE_LEN长度后,就不能继续添加菜单项了,请读者思考一下怎样才能做到动态增长。

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:http://yiguibugui.taobao.com/

315

主题

1645

帖子

4

粉丝