专栏首页Albert陈凯2018-07-19 如何重构“箭头型”代码如何重构“箭头型”代码

2018-07-19 如何重构“箭头型”代码如何重构“箭头型”代码

原文地址:https://coolshell.cn/articles/17757.html

如何重构“箭头型”代码

本文主要起因是,一次在微博上和朋友关于嵌套好几层的if-else语句的代码重构的讨论(微博原文),在微博上大家有各式各样的问题和想法。按道理来说这些都是编程的基本功,似乎不太值得写一篇文章,不过我觉得很多东西可以从一个简单的东西出发,到达本质,所以,我觉得有必要在这里写一篇的文章。不一定全对,只希望得到更多的讨论,因为有了更深入的讨论才能进步。

文章有点长,我在文章最后会给出相关的思考和总结陈词,你可以跳到结尾。

所谓箭头型代码,基本上来说就是下面这个图片所示的情况。

image

那么,这样“箭头型”的代码有什么问题呢?看上去也挺好看的,有对称美。但是……

关于箭头型代码的问题有如下几个:

1)我的显示器不够宽,箭头型代码缩进太狠了,需要我来回拉水平滚动条,这让我在读代码的时候,相当的不舒服。

2)除了宽度外还有长度,有的代码的if-else里的if-else里的if-else的代码太多,读到中间你都不知道中间的代码是经过了什么样的层层检查才来到这里的。

总而言之,“箭头型代码”如果嵌套太多,代码太长的话,会相当容易让维护代码的人(包括自己)迷失在代码中,因为看到最内层的代码时,你已经不知道前面的那一层一层的条件判断是什么样的,代码是怎么运行到这里的,所以,箭头型代码是非常难以维护和Debug的

微博上的案例 与 Guard Clauses

OK,我们先来看一下微博上的那个示例,代码量如果再大一点,嵌套再多一点,你很容易会在条件中迷失掉(下面这个示例只是那个“大箭头”下的一个小箭头)

这种代码的重构方式叫 Guard Clauses

这里的思路其实就是,让出错的代码先返回,前面把所有的错误判断全判断掉,然后就剩下的就是正常的代码了

抽取成函数

微博上有些人说,continue 语句破坏了阅读代码的通畅,我觉得他们一定没有好好读这里面的代码,其实,我们可以看到,所有的 if 语句都是在判断是否出错的情况,所以,在维护代码的时候,你可以完全不理会这些 if 语句,因为都是出错处理的,而剩下的代码都是正常的功能代码,反而更容易阅读了。当然,一定有不是上面代码里的这种情况,那么,不用continue ,我们还能不能重构呢?

延伸思考

对于 if-else 语句来说,一般来说,就是检查两件事:错误状态

检查错误

对于检查错误来说,使用 Guard Clauses 会是一种标准解,但我们还需要注意下面几件事:

1)当然,出现错误的时候,还会出现需要释放资源的情况。你可以使用 goto fail;这样的方式,但是最优雅的方式应该是C++面向对象式的 RAII 方式。

2)以错误码返回是一种比较简单的方式,这种方式有很一些问题,比如,如果错误码太多,判断出错的代码会非常复杂,另外,正常的代码和错误的代码会混在一起,影响可读性。所以,在更为高组的语言中,使用 try-catch 异常捕捉的方式,会让代码更为易读一些。

检查状态

对于检查状态来说,实际中一定有更为复杂的情况,比如下面几种情况:

1)像TCP协议中的两端的状态变化。

2)像shell各个命令的命令选项的各种组合。

3)像游戏中的状态变化(一棵非常复杂的状态树)。

4)像语法分析那样的状态变化。

对于这些复杂的状态变化,其本上来说,你需要先定义一个状态机,或是一个子状态的组合状态的查询表,或是一个状态查询分析树。

写代码时,代码的运行中的控制状态或业务状态是会让你的代码流程变得混乱的一个重要原因,重构“箭头型”代码的一个很重要的工作就是重新梳理和描述这些状态的变迁关系

总结

好了,下面总结一下,把“箭头型”代码重构掉的几个手段如下:

1)**使用 Guard Clauses **。 尽可能的让出错的先返回, 这样后面就会得到干净的代码。

2)把条件中的语句块抽取成函数。 有人说:“如果代码不共享,就不要抽取成函数!”,持有这个观点的人太死读书了。函数是代码的封装或是抽象,并不一定用来作代码共享使用,函数用于屏蔽细节,让其它代码耦合于接口而不是细节实现,这会让我们的代码更为简单,简单的东西都能让人易读也易维护,写出让人易读易维护的代码才是重构代码的初衷

3)对于出错处理,使用try-catch异常处理和RAII机制。返回码的出错处理有很多问题,比如:A) 返回码可以被忽略,B) 出错处理的代码和正常处理的代码混在一起,C) 造成函数接口污染,比如像atoi()这种错误码和返回值共用的糟糕的函数。

4)对于多个状态的判断和组合,如果复杂了,可以使用“组合状态表”,或是状态机加Observer的状态订阅的设计模式。这样的代码即解了耦,也干净简单,同样有很强的扩展性。

5) 重构“箭头型”代码其实是在帮你重新梳理所有的代码和逻辑,这个过程非常值得为之付出。重新整思路去想尽一切办法简化代码的过程本身就可以让人成长。

(全文完)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 2019-03-14 面向未来编程:如何平衡代码的可读性和扩展性

    在今天的世界里,软件往往会在其整个生命周期内增加许多功能。为了处理永久的软件,软件工程师必须编写可维护的代码。可维护的代码有两个我们关心的属性:可读性,易于理解...

    Albert陈凯
  • 2018-08-24 大公司为什么还在采用过时的技术!

    https://mp.weixin.qq.com/s/-1VPme1Eb_ItA4ej6_Ghsw

    Albert陈凯
  • Hadoop离线数据分析平台实战——350公用代码重构Hadoop离线数据分析平台实战——350公用代码重构

    Hadoop离线数据分析平台实战——350公用代码重构 项目进度 模块名称 完成情况 用户基本信息分析(MR)� 完成 浏览器信息分析(MR)...

    Albert陈凯
  • 自建 GitLab 似乎很简单?这些坑也许你不知道

    码云Gitee
  • Xcode创建可复用的代码块 原

            在各种程序开发中,编写代码的效率是非常重要的一个问题,各种优秀的编译器也都有相应的插件用于提高程序员的编码速度。在xcode中,可以通过定义代码...

    珲少
  • 优秀程序员是如何处理糟糕代码的

    优秀程序员是如何处理糟糕代码的 可能你一行不好的代码也从来没有写过。这是有可能的,但在现实中又不太可能。 现实情况是,和这个星球上的其他所有程序员一样,你会产出...

    用户1289394
  • 不朽经典,无我编程的十大戒律

      无我编程的十大戒律最早出现在 1971 年 Gerald Weinberg 出版的《 程序开发心理学 》里。后由 Stack Overflow 网站的联合创...

    用户1289394
  • 为什么大公司还在用过时的技术?

    本文出自一朋友给我的提问,于是博主呕心沥血给他花式洗脑了几个小时。忽然发现,应该还有许多朋友有同样的疑问。所以整理成文。

    Java技术栈
  • 为什么vjudge上他人公开的代码要以图片形式显示?

    vjudge用图片来显示代码,应该是为了避免抄袭。在较低水平的oier中,已经有交别人的代码来通过题目的风气。举个例子,洛谷上抄袭代码情况极其严重,而u...

    ACM算法日常
  • 编程与写作

    王小波广为人知的身份是作家,而他在写小说之前是一个相当优秀的程序员。他应该是程序员中最会写作,作家中最懂编程的人。

    章鱼喵

扫码关注云+社区

领取腾讯云代金券