表驱动法

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. http://blog.csdn.net/sdksdk0/article/details/50749326

    http://blog.csdn.net/sdksdk0/article/details/50749326

  2. PHP超时提示Fatal error: Maximum execution time of 30,解决方案

    PHP执行超时提示如下:Fatal error: Maximum execution time of 30 seconds exceeded in D:\php\AppServ\www\sum3\te ...

  3. C# 模拟登陆

    原理 我们知道,一般需要登录的网站,服务器和客户端都会有一段时间的会话保持,而这个会话保持是在登录时候建立的, 服务端和客户端都会持有这个KEY,在后续访问时,都需要核对这两个KEY是否一致. 而客户 ...

  4. Linux-部署ftp

    通过外部window ftp 客户端 访问linux 有两种方法 方法一:Linux系统未安装vsftp 服务 这个是本人使用的ftp客户端的版本号 启动ftp客户端,填写ip ,账号,密码 问题:当 ...

  5. 【ABAP系列】SAP ABAP 宏的简单使用

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 宏的简单使用 ...

  6. 【ABAP系列】SAP ABAP 优化LOOP循环的一点点建议

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 优化LOOP循 ...

  7. 006/搭建fabric(二)

    准备vmware虚拟机,并安装完ubuntu系统后.继续搭建fabric运行环境... 0.打开终端,切换root身份.目的:后续操作即可不用sudo... 右键->open Terminal- ...

  8. SpringBoot 使用logback

    1.添加pom引用 <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback ...

  9. 实列+JVM讲解类的实列化顺序

    刨根问底---类的实列化顺序 开篇三问 1什么是类的加载,类的加载和类的实列有什么关系,什么时候类加载 2类加载会调用构造函数吗,什么时候调用构造函数 3什么是实列化对象,实列化的对象有什么东西. 我 ...

  10. Good number(3进制)

    https://codeforces.com/problemset/problem/1249/C2 C2. Good Numbers (hard version) time limit per tes ...