表驱动方法

来源:互联网 发布:手机淘宝口令 编辑:程序博客网 时间:2024/06/05 19:41

       上周接本上都浸泡在表驱动方法里,重构了一块多年的代码,说是多年,其实也就是一年半左右的样子:-)不过当我看到那些代码的时候,震惊到了。代码相当杂乱,整个功能模块就是一个大的hard code,解决问题的方式十分的hack,这里取hack的贬义~代码最初是很简单的,稍微hard一点的解决方案确实不是很刺眼,尤其对于应用来说,追求功能的发布速度几乎是第一要义,所以当初开发的时候也没有注意设计,怎么方便怎么来。可是后来pm各种加feature,尤其是换了好几个pm后,这块的逻辑就已经抗不住各种折腾了。我之前尝试过重构一次,不过当初才疏学浅(其实现在也没好到哪去==!)基本上只是整理了一下代码,没能完成真正意义上的重构。这次由于要加入新的功能,实在是加不进去了。所以只能硬着头皮重构。幸好,最近在开始阅读《代码大全》,按照导读,正好一开是就看了表驱动方法,如获至宝!又顺带阅读了下《java编程思想》关于枚举的一章。一时叹息,当初怎么没有好好读读书啊!表驱动方法基本上解决了我长久对于复杂逻辑处理的困惑。这里mark 一下。(例子均来源于《代码大全》代码可能有我自己修改在其中。)

       所谓的表驱动方法其实很简单,就是构造一张表,然后从中查找出需要的结果。这个道理我也早就懂,可是从来没有真正掌握真正奥义。比如说,我们想知道一年中的每个月的天数,不关心润年的情况。如果是我,可能会不假思索就写出下面的代码

public int getDayNumber(int month) {   switch (month) {       case 1:        return 31;       case 2:        return 28;                ...               case 12:         return 31;    }}

      里面用到了switch语句已经朝整洁的代码小步前进了一丢丢了。如果是再早一点的我,可能就直接上了12个if else语句了!当然switch 和if else也没有太本质的区别,性能都是一样的,只是switch看起来稍微好看一点而已。这里我做了省略,因为实在不想写那么多的重复代码。然而如果用查找表的方式代码就变成了下面的样子

private static int[] DAYS_NUMBER = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};public int getDayNumber(int month) {    return DAYS_NUMBER[month - 1];}

      瞬间代码高效简洁了起来!当然,这里应该有一些边界判断,但是核心的代码就是这么几行,而且数组查找的效率明显要比用12个if 判断的高多了。当看到这一段的时候我已经被表驱动方法深深吸引住了。对代码的可维护性和清晰度来说,都是质的飞跃!而且这还是最简单的表驱动方法,直接查找表。还有索引访问和阶梯访问,分别对应于复杂情况不同的逻辑查找方式。昨晚co的很晚,今天想早点睡,就不详细写其他两种表驱动方法了~

     另一个想记录的就是java 枚举的用法。以前一直都是把枚举仅仅用来当作常量的替代品。仔细看了《java编程思想》中关于枚举的应用之后才发现,以前太naive了。首先,枚举类型就可以作为普通类来用的(当然不是说可以new 出来),可以有自己的公共方法,私有方法,域等等。而且可以定义抽象方法,然后在声明各个枚举的时候实现这些方法。EnumMap使用枚举类型作为键值,而且其性能和数组相同,因为它本身的内部实现就是用数组实现的。这些特性放在一起让枚举类型成为实现表驱动方法的非常好的途径。在我的现实问题中,我就是定义了一个枚举类型和一下抽象方法,这些抽象方法用来对应不同元素的行为,另外定义了一个枚举作为不同元素的行为触发的条件判断。然后把这两个枚举通过遍历的方式放到一张EnumMap中实现了表的构造。在后续的应用中就只需要通过查找表就可以获得想要的元素了。当然,实际的实现要比这个复杂一些,不过基本思路就是这样。在我定义了表之后,我就可以非常方便的调整元素顺序,或者修改相应的触发条件或者行为。代码的可维护性上升很多。

      所以说经典就是经典,前辈们在长期的实践中总结出的一套方法可以避免我们走很多弯路。需要满怀敬畏的去学习前辈们的思想。


0 0