• 2010-11-04

    代码之丑(三)

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/82256362.html

    又见switch:
      switch(firstChar) {
      case ‘N’:
        nextFirstChar = ‘O’;
        break;
      case ‘O’:
        nextFirstChar = ‘P’;
        break;
      case ‘P’:
        nextFirstChar = ‘Q’;
        break;
      case ‘Q’:
        nextFirstChar = ‘R’;
        break;
      case ‘R’:
        nextFirstChar = ‘S’;
        break;
      case ‘S’:
        nextFirstChar = ‘T’;
        break;
      case ‘T’:
        throw Ebusiness();
      default:
      }

    出于多年编程养成的条件反射,我对于switch总会给予更多的关照。研习面向对象编程之后,看见switch就会想到多态,遗憾的是,这段代码和多态没什么关系。仔细阅读这段代码,我找出了其中的规律,nextFirstChar就是firstChar的下一个字符。于是,我改写了这段代码:
      switch(firstChar) {
      case ‘N’:
      case ‘O’:
      case ‘P’:
      case ‘Q’:
      case ‘R’:
        nextFirstChar = firstChar + 1;
        break;
      case ‘T’:
        throw Ebusiness();
      default:
      }

    现在,至少看起来,这段代码已经比原来短了不少。当然这么做基于一个前提,也就是这些字母编码的顺序确确实实连续的。从理论上说,开始那段代码适用性更强。但在实际开发中,我们碰到字母不连续编码的概率趋近于0。

    但这段代码究竟是如何产生的呢?我开始研读上下文,原来这段代码是用当前ID产生下一个ID的,比如当前是N0000,下一个就是N0001。如果数字满了,就改变字母,比如当前ID是R9999,下一个就是T0000。在这里,字母也就相当于一位数字,根据情况进行进位,所以有了这段代码。

    代码上的注释告诉我,字母的序列只有从N到T,根据这个提示,我再次改写了这段代码:
      if (firstChar >= ‘N’ && firstChar <= ‘S”) {
        nextFirstChar = firstChar + 1;
      } else {
        throw Ebusiness();
      }

    这里统一处理了字母为T和default的情形,严格说来,这和原有代码并不完全等价。但这是了解了需求后做出的决定,换句话说,原有代码在这里的处理中存在漏洞。

    修改这段代码,只是运用了非常简单的编程技巧。遗憾的是,即便如此简单的编程技巧,也不是所有开发人员都驾轻就熟的,很多人更习惯于“平铺直叙”。这种直白造就了代码中的许多鸿篇巨制。我听过不少“编程是体力活”的抱怨,不过,能把写程序干成体力活,也着实不值得同情。写程序,不动脑子,不体力才怪。

    无论何时何地,只要switch出现在眼前,请提高警惕,那里多半有坑。


    本文已经首发于InfoQ中文站 ,版权所有,原文为《专栏:代码之丑(三) 》,如需转载,请务必附带本声明,谢谢。

    InfoQ中文站 是一个面向中高端技术人员的在线独立社区,为Java、.NET、Ruby、SOA、敏捷、架构等领域提供及时而有深度的资讯、高端技术大会如QCon 、免费迷你书下载如《架构师 》等。

    分享到:

    历史上的今天:

    QCon上海随想 2013-11-04
    引用地址:

    评论

  • 我觉得switch一般可以用一些map的结构来增加代码的可读性,比如上面的例如如果有个:
    map = {'N':'O', 'O':'P' ...} 这样的结构的话,直接用map(firstChar)就可以获取值了,以后要扩展增加就修改这个map。

    同样的道理也可以应用于一些消息响应的函数分发当中,只不过把map的value改成函数对象而已。
  • 最近一直在和丑陋的代码作斗争,感觉一些想说又不知道表达的东西让你说出来了
  • 一直在关注,不断在学习
  • 我赞同原来的switch比较丑,改成后面的就好很多。我觉得原来的switch最致命的缺陷在于重复,修改后的消除了这个重复。

    但是我突然想起一个问题,我们讲好代码要很好的体现设计和业务,不需要用户拐弯抹角,就能够看出编码者的意图。这是不是也说明写代码过程中,也需要一点点直白呢?当然,我们不能把这个作为不动脑筋体力活似的编码的借口。
    回复sinojelly说:
    直白是对的,但这和把代码写好是不矛盾的。事实上,写得越好的代码是越清楚的,而很多丑陋的代码只是打着直白的旗号而已。
    2010-11-07 20:32:17
  • 学习了!