本文示例代码采用的是c语言。

之前介绍过数据驱动编程《什么是数据驱动编程》。里面介绍了一个简单的数据驱动手法。今天更进一步,介绍一个稍微复杂,更加实用的一点手法——表驱动法。
关于表驱动法,在《unix编程艺术》中有提到,更详细的描述可以看一下《代码大全》,有一章专门进行描述(大概是第八章)。

简单的表驱动:
《什么是数据驱动编程》中有一个代码示例。它其实也可以看做是一种表驱动手法,只不过这个表相对比较简单,它在收到消息后,根据消息类型确定使用调用什么函数进行处理。

复杂一点的表驱动:

考虑一个消息(事件)驱动的系统,系统的某一模块需要和其他的几个模块进行通信。它收到消息后,需要根据消息的发送方,消息的类型,自身的状态,进行不同的处理。比较常见的一个做法是用三个级联的switch分支实现通过硬编码来实现:

[cpp] view plaincopy
  1. switch(sendMode)
  2. {
  3. case:
  4. }
  5. switch(msgEvent)
  6. {
  7. case:
  8. }
  9. switch(myStatus)
  10. {
  11. case:
  12. }

这种方法的缺点:
1、可读性不高:找一个消息的处理部分代码需要跳转多层代码。
2、过多的switch分支,这其实也是一种重复代码。他们都有共同的特性,还可以再进一步进行提炼。
3、可扩展性差:如果为程序增加一种新的模块的状态,这可能要改变所有的消息处理的函数,非常的不方便,而且过程容易出错。
4、程序缺少主心骨:缺少一个能够提纲挈领的主干,程序的主干被淹没在大量的代码逻辑之中。

用表驱动法来实现:
根据定义的三个枚举:模块类型,消息类型,自身模块状态,定义一个函数跳转表:

[cpp] view plaincopy
  1. typedef struct  __EVENT_DRIVE
  2. {
  3. MODE_TYPE mod;//消息的发送模块
  4. EVENT_TYPE event;//消息类型
  5. STATUS_TYPE status;//自身状态
  6. EVENT_FUN eventfun;//此状态下的处理函数指针
  7. }EVENT_DRIVE;
  8. EVENT_DRIVE eventdriver[] = //这就是一张表的定义,不一定是数据库中的表。也可以使自己定义的一个结构体数组。
  9. {
  10. {MODE_A, EVENT_a, STATUS_1, fun1}
  11. {MODE_A, EVENT_a, STATUS_2, fun2}
  12. {MODE_A, EVENT_a, STATUS_3, fun3}
  13. {MODE_A, EVENT_b, STATUS_1, fun4}
  14. {MODE_A, EVENT_b, STATUS_2, fun5}
  15. {MODE_B, EVENT_a, STATUS_1, fun6}
  16. {MODE_B, EVENT_a, STATUS_2, fun7}
  17. {MODE_B, EVENT_a, STATUS_3, fun8}
  18. {MODE_B, EVENT_b, STATUS_1, fun9}
  19. {MODE_B, EVENT_b, STATUS_2, fun10}
  20. };
  21. int driversize = sizeof(eventdriver) / sizeof(EVENT_DRIVE)//驱动表的大小
  22. EVENT_FUN GetFunFromDriver(MODE_TYPE mod, EVENT_TYPE event, STATUS_TYPE status)//驱动表查找函数
  23. {
  24. int i = 0;
  25. for (i = 0; i < driversize; i ++)
  26. {
  27. if ((eventdriver[i].mod == mod) && (eventdriver[i].event == event) && (eventdriver[i].status == status))
  28. {
  29. return eventdriver[i].eventfun;
  30. }
  31. }
  32. return NULL;
  33. }

这种方法的好处:
1、提高了程序的可读性。一个消息如何处理,只要看一下驱动表就知道,非常明显。
2、减少了重复代码。这种方法的代码量肯定比第一种少。为什么?因为它把一些重复的东西:switch分支处理进行了抽象,把其中公共的东西——根据三个元素查找处理方法抽象成了一个函数GetFunFromDriver外加一个驱动表。
3、可扩展性。注意这个函数指针,他的定义其实就是一种契约,类似于java中的接口,c++中的纯虚函数,只有满足这个条件(入参,返回值),才可以作为一个事件的处理函数。这个有一点插件结构的味道,你可以对这些插件进行方便替换,新增,删除,从而改变程序的行为。而这种改变,对事件处理函数的查找又是隔离的(也可以叫做隔离了变化)。、
4、程序有一个明显的主干。
5、降低了复杂度。通过把程序逻辑的复杂度转移到人类更容易处理的数据中来,从而达到控制复杂度的目标。

继承与组合
考虑一个事件驱动的模块,这个模块管理很多个用户,每个用户需要处理很多的事件。那么,我们建立的驱动表就不是针对模块了,而是针对用户,应该是用户在某状态下,收到某模块的某事件的处理。我们再假设用户可以分为不同的级别,每个级别对上面的提到的处理又不尽相同。
用面向对象的思路,我们可以考虑设计一个用户的基类,实现相同事件的处理方法;根据级别不同,定义几个不同的子类,继承公共的处理,再分别实现不同的处理。这是最常见的一种思路,可以叫它继承法。
如果用表驱动法怎么实现?直接设计一个用户的类,没有子类,也没有具体的事件的处理方法。它有一个成员,就是一个驱动表,它收到事件后,全部委托给这个驱动表去进行处理。针对用户的级别不同,可以定义多个不同的驱动表来装配不同的对象实例。这个可以叫他组合法。
继承和组合在《设计模式》也有提到。组合的优势在于它的可扩展性,弹性,强调封装性。(继承和组合可以参考这篇文章:面向对象之继承组合浅谈)
至于这种情况下的驱动表,可以继续使用结构体,也可以使用对象。

上面的方法的一点性能优化建议:

如果对性能要求不高,上面的方法足可以应付。如果性能要求很高,可以进行适当的优化。比如,可以建立一个多维数组,每一维分别表示模块,状态,消息。这样,就可以根据这三者的枚举直接根据下标定位到处理函数,而不是查表。(其实还是数据驱动的思想:数据结构是静态的算法。)

转自:http://blog.csdn.net/chgaowei/article/details/6966857

转载于:https://www.cnblogs.com/organic/p/5005646.html

数据驱动编程之表驱动法相关推荐

  1. 数据驱动编程与表驱动法(多if-else结构精简)

    转载链接地址 http://tec.5lulu.com/detail/108asn4wm11y68sdc.html 1数据驱动编程的核心 数据驱动编程的核心出发点是 相对于程序逻辑,人类更擅长于处理数 ...

  2. c++ 哈希表_C语言精华知识:表驱动法编程实践

    问:怎么每天看到这种文章? 答:只需搜索公众号"51单片机学习网"免费关注 排版:嵌入式云IOT技术圈 数据压倒一切.如果选择了正确的数据结构并把一切组织的井井有条,正确的算法就不 ...

  3. c 数组上限_深度文章,高手必看:C编程表驱动法编程实践(精华帖,建议收藏并实践)...

    直接来源 :公众号[嵌入式云IOT技术圈],作者:杨源鑫数据压倒一切.如果选择了正确的数据结构并把一切组织的井井有条,正确的算法就不言自明.编程的核心是数据结构,而不是算法.--Rob Pike 说明 ...

  4. C语言表驱动法编程实践

    数据压倒一切.如果选择了正确的数据结构并把一切组织的井井有条,正确的算法就不言自明.编程的核心是数据结构,而不是算法. --Rob Pike  说明 本文基于这样的认识:数据是易变的,逻辑是稳定的. ...

  5. java 表驱动_表驱动法编程(数据驱动)

    所谓表驱动法(Table-Driven Approach),简单讲是指用查表的方法获取值. 我们平时查字典以及念初中时查<数学用表>找立方根就是典型的表驱动法.在数值不多的时候我们可以用逻 ...

  6. 编程模式(schema) —— 表驱动法(table-driven)

    使用表驱动法,而非繁琐冗长的 if/else, switch case(本身也代表一种代码坏味道),也是替身编程质量的重要手段, 表驱动法是一种编程模式(schema)-- 从表里面查找信息而不使用逻 ...

  7. 事件驱动编程、消息驱动编程、数据驱动编程

    事件驱动 基本概念 窗口/组件 事件 消息(队列) 事件响应(服务处理程序) 调度算法 进程/线程 非阻塞I/O 程序的执行可以看成对CPU,内存,IO资源一次占用 现代操作系统支持多任务,可以分时复 ...

  8. java表驱动法索引访问_表驱动法 - SegmentFault 思否

    在我们平时的开发中,if else是最常用的条件判断语句.在一些简单的场景下,if else用起来很爽,但是在稍微复杂一点儿的逻辑中,大量的if else就会让别人看的一脸蒙逼. 如果别人要修改或者新 ...

  9. 软件系统设计 表驱动法

    表驱动法 表驱动是一种编程模式(scheme) pattern 是可以被实例化的 scheme 是一种方式 当我需要有很复杂的逻辑判断的时候,我不会直接写出来,而是通过表中的数据来进行. 表可以放在文 ...

最新文章

  1. 进程控制概念简介 多线程上篇(三)
  2. Win 2003的“远程桌面”需要进一步管理
  3. 计算机视觉大规模爆发,6大细分领域将撑起725亿元市场
  4. C++中#include<fstream>头文件
  5. P2955 [USACO09OCT]奇数偶数Even? Odd?
  6. XGBClassifier()特征选择
  7. 计算机中2的四次方为啥是4位,计算机基础试题2(4页)-原创力文档
  8. TCP模块如何处理连接包
  9. 人工智能与人的职业发展
  10. 小米cc9出厂线刷包_小米cc9 pro刷机教程,线刷升级更新官方系统包
  11. 计算机文献检索综合性实验报告,文献检索实验报告.doc
  12. 【软件推荐】还用着Windows自带的看图软件吗?
  13. 芯片解密什么是物联网芯片,与普通芯片有什么不同?
  14. 室内定位技术之UWB篇
  15. 什么是敏捷开发Scrum
  16. 灰色简约大学生小组作业展示PPT模板
  17. wince下SD卡驱动开发
  18. 商业地产数字化转型分析
  19. 诺基亚发布NetAct云网络管理系统,为5G网络演进铺路
  20. 大于4GB镜像文件刻录方法

热门文章

  1. RSA加密解密(附源码工程)
  2. android view 存值,使用ViewModel保存数据
  3. python文本数据处理_python 数据处理 对txt文件进行数据处理
  4. trueOS能装linux软件,GhostBSD 19.09 发布,使用来自TrueOS软件包
  5. 微信小程序轮播中的current_开源 | 微信接龙小程序 wechatsolita 开源
  6. 单按钮启停电路实物图_手绘220V清洗机电路原理图和接线方法,单相电机常见故障排查...
  7. 用python海龟制图画花瓣_Python教程:使用Turtles画出带有花瓣的花
  8. 7种寻址方式,以及有效地址计算方法。
  9. Shell date指令
  10. js处理web页面滚动条