表驱动法

1、相信很多刚从事工作的程序员或一些初级程序员在写代码的时候会出现对一些逻辑判断写成多层if-else嵌套的经历,这种方式在一些简单的层次中运用起来确实可行,但对于一些大型项目逻辑判断比较多的情况下,一下子嵌套十几个甚至更多的if-else就会显得吃力、混乱,降低了可读性。因此今天我要介绍一种代替if-else的方式-----表驱动法。

2、相对比于switch-case这种方式,表驱动法会更有效些;使用表驱动可以提高源程序的可读性,使之更简洁而且更容易修改与扩充。

3、对于表驱动方式根据其复杂度可以分为三种:(1)直接访问(2)索引访问(3)阶梯访问(分段查找)

4、使用表驱动时候的两个问题:

(1)

(2)

5、表驱动的另外一个优势就是:你可以把表里里面的数据存放在一个单独的文件中,当程序运行到这里的时候会自动去读取文件中的内容,我们就可以在数据改变的情况下不改变源程序,而只改变文件中的数据即可,这样也可以实现数据的便捷扩充,使得数据与程序分离开来,降低耦合度。

6、

以上图片内容摘录自《代码大全》一书18章。

7、表驱动应用实例:(类比中断向量表,函数指针指向函数实现

代码示例(1):

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

  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、程序缺少主心骨:缺少一个能够提纲挈领的主干,程序的主干被淹没在大量的代码逻辑之中。

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

typedef struct  __EVENT_DRIVE

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

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

代码示例(2):

博客   :http://www.cnblogs.com/clover-toeic/p/3730362.html

--------------2017.7.9

(1)消灭初级程序员常用的多层if-else嵌套--------------【表驱动法】的更多相关文章

  1. Java进阶之路——从初级程序员到架构师,从小工到专家

    原创文章 怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序员也是工作三五年之后开始迷茫的老程序员经常会问到 ...

  2. 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)

    本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...

  3. 为什么要重写hashcode和equals方法?初级程序员在面试中很少能说清楚。

    我在面试 Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候选人直接说没写过.我就想,或许真的没写过,于是就再通过一个问题确认:你在用HashMap的时候,键(Key)部分, ...

  4. JAVA程序员常用英语

    JAVA程序员常用英语 干程序员这行实在是离不开英语,干程序员是一项很辛苦的工作,要成为一个高水平的程序员尤为艰难.这是因为计算机软件技术更新的速度越来越快,而这些技术大多来源于英语国家,我们在引进这 ...

  5. 【常用软件】木木的常用软件点评(2)------VC程序员常用工具篇

     摘自:http://blog.csdn.net/liquanhai/article/details/7215045 木木的常用软件点评(2)------VC程序员常用工具篇 分类: VC++经验总结 ...

  6. Java程序员常用工具类库

    有人说当你开始学习Java的时候,你就走上了一条不归路,在Java世界里,包罗万象,从J2SE,J2ME,J2EE三大平台,到J2EE中的13中核心技术,再到Java世界中万紫千红的Framework ...

  7. Java程序员常用的@Component、@Repository、@Controller、@Service系列【案例demo3】

    Java程序员常用的@Component.@Repository.@Controller.@Service系列[案例demo3]   很多程序员通过在类上使用@Repository.@Componen ...

  8. [译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中的Value 学习笔记——异步 程序员常说的「哈希表」是个什么鬼?

    [译]聊聊C#中的泛型的使用(新手勿入)   写在前面 今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发 ...

  9. C#130问,初级程序员的面试宝典

    首先介绍下,目前C#作为一门快速开发的语言,在面试的过程中需要注意的技术知识点,了解下面的知识点对于初级工程师入职非常有帮助,也是自己的亲身体悟. 1.    简述 private. protecte ...

随机推荐

  1. 16/7/8_PHP-对象的高级特性

    对这个理解不太懂或者说 没有一个明确的用法,不知道该怎么使用,说到底还是不懂有什么用.我还是先把只是点复制过来 对象比较,当同一个类的两个实例的所有属性都相等时,可以使用比较运算符==进行判断,当需要 ...

  2. kali安装教程

    首先在vm里面新建虚拟机,直接选择典型,然后下一步.   1   2 然后到了这一步,选择中间的安装程序光盘镜像文件,然后去文件里面找你自己下载的镜像,这时候可能系统会出现无法检测此光盘镜像中的操作系 ...

  3. Java设计模式——建造者模式(创建型模式)

    概述   建造者模式也称为生成器模式,是一种对象创建型模式,它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象.   建造者模式意在为重叠构造 ...

  4. 关于服务器无法在已发送http表头之后设置状态问题

    Response.ClearHeaders()方法 ClearHeaders方法只删除头信息,而不删除Response显示输出信息. this.Response.BufferOutput = true ...

  5. c# 对象相等性和同一性

    一:对象相等性和同一性 System.Object提供了名为Equals的虚方法,作用是在两个对象包含相同值的前提下返回true,内部实现 public class Object { public v ...

  6. python基础-6.2正则表达式,计算器练习

    content = "1-2*((60-30+(1-40/5*5+3-2*5/3)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))&q ...

  7. spring源码下载及转入ECLIPSE

    转自:https://www.cnblogs.com/scevecn/p/6043284.html 本例spring源码版本是4.3.0的, 所以jdk需要准备1.8的(不同版本源码要求的jdk不一样 ...

  8. RocketMQ安装部署及整合Springboot

    消息中间件的功能: 通过学习ActiveMq,kafka,rabbitMq这些消息中间件,我们大致能为消息中间件的功能做一下以下定义:可以先从基本的需求开始思考 最基本的是要能支持消息的发送和接收,需 ...

  9. Socket服务端和客户端文件传输

    很多朋友在使用socket编程时不可避免的都做过文件传输,而视频电影等需要一个字节一个字节的传输:但是客户端一般都通过-1进行终止,服务也一样:但是存在的问题是客户端永远不会把-1传递给服务端:因此经 ...

  10. C# 同步调用 异步调用 异步回调 多线程的作用

    同步调用   : 委托的Invoke方法用来进行同步调用.同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行. 异步调用  :同步调用会阻塞线程,如果是要调用一项繁重的 ...