可读代码编写炸鸡九 - 抽取子问题
大家好,我是多选参数的一员 —— 大炮。
原本想专门写个第三层的简介,但篇幅过短,也不会多少人看,就在本篇炸鸡简略提一下,然后便进入第三层的第一篇炸鸡就好。
我们回顾一下,可读代码编写第二层主要是讲了 代码逻辑 上的优化。
第三层便是更大的范围了,是关于代码组织,可以说是函数级别的代码组织优化。
其实第三层还是可以分成两个部分:
当你面对已经出现的不好代码该咋办
在你写代码前如何尽量避免不好代码
废话不多说,先上一个第三层的概览导图:
后台回复 「第三层」获取源文件
所以本篇炸鸡从 抽取不相关的子问题 这一点入手可读代码编写。
写在前头
对于代码的编写,大事化小,小事化了。模块化是我们很需要的一个思想。
本篇炸鸡主要是讲 提取无关的子问题。
公众号后台回复 「抽取」获得源 pdf 文件
为了达成这个目标,来个自问三连。
看一下整个代码块或者一个函数,问一下自己,这个代码的 最终目的 是什么?
对于代码的每一行,问一下自己,这样对这个目标有 直接作用 吗。还是这代码用于解决其他的不相关的子问题。
如果解决不相关的子问题的代码开始变多,问一下自己,是不是需要提取,封装为函数。
本炸鸡主要关注:不相关的子问题的提取。所以本炸鸡需要提供不同条件下的例子,来阐述提取的技术。
而这个不相关的子问题,并不是和代码目的毫无干系的代码块,而是 篇幅过大,但解决的问题只是很小一部分 的代码块。
芜湖,如何抽取
首先要抽取不相关的子问题之前,得知道啥是不相关的子问题?
可以参考在上文的自问三连中的第一问:
也就是与最终目的相关性不高的代码,都可以算作不相关的子问题,是附着代码。
我们看一段代码:
我用了一个比较抽象的代码,这段代码目标是 wananDoA,也就是做 A
相关的事情,但是函数里充斥着大量的解决其他子问题的附着代码 B
和 C
。
所以就需要将 B
和 C
相关代码抽取,比如这样:
我们可以发现,抽取完的代码整体:
不占用调用函数的篇幅
专注调用函数目标
被抽取代码拥有更好的拓展性,解耦合
其实抽取子问题的核心实现就是这样而已。今天的炸鸡到此结束,谢谢大家。
我开玩笑的兄弟,再接一些具体的抽取方法吧。
工具代码
大概各位的项目中都会有一个 「工具人」模块。就是存放一些工具代码,供各开发人员使用。
例如,字符串操作,日期操作等等,这些完全可以抽取为工具代码。
如下代码是游戏跨天要做的事情:
如果再结算的逻辑中,需要判断玩家的活跃时间是否在指定的时间区间内,同时需要知道玩家的最近上线时间与上一次离线时间是否在同一天。
很明显,上述代码的结算逻辑中,判断时间区间,是否同一天等一系列逻辑都是 篇幅大,但是解决的问题是很小的 代码逻辑,也是复用性很强的代码,也就是前头说的 实用工具代码。
这些正是 相关性较小的子问题。
我们将其分出来。
于是原本的代码被简化为:
芜湖,多了几个工具代码,还缩小了函数篇幅,岂不美哉。
简化已有接口
什么是已有接口呢。其实这也有两个情况。
一个是语言层面已有的接口不能适应项目需求,导致一些函数体量得到不必要的增加。
我拿 lua
举例,lua
中只有一个复杂的数据结构叫做 table
。table
有相应的 table
库对其操作,但是不存在一个清空操作。如果在一串代码中,我需要清空一个 table
,那我得写这样的代码:
所以我还不如对 table
这个库再加一个 clear
方法。
还有一种情况,面对现有接口,参数过多的情况:
针对现有业务功能,完全可以在此接口上再封装一层接口:
所以面对已有的接口,完全可以再进行包装。对于代码可读性来说,还是对调用的方便来说,都是有裨益的。
而且其实在调用方便这一层面,利用函数合适的命名,也是增强了代码的可读性。
不要过分抽取
看完前面的内容,最怕的情况是过度抽取。
看一下如下的抽象代码:
我们可以看到,抽取了多个子问题,反而需要我们不断地跳转查看具体逻辑,反而增加了思想包袱,违背 明确函数目标 的初心。
总结
好了,这篇炸鸡算是到结尾了,其实这个炸鸡最关键的就是。
阅读者注意力。
函数的目的。
篇幅。
所以为了使阅读者专注于函数的目的,我们需要将对于目的而言 相关性较小的子问题 抽取出来,变成一个独立的函数,甚至是库。这个取决于这个子问题使用的范围是一个文件,还是一整个项目。
本篇炸鸡基于此,罗列了许多抽取不同子问题的不同情况,但是总而言之,便是合理地将代码块抽取和封装。
版权声明: 本文为 InfoQ 作者【多选参数】的原创文章。
原文链接:【http://xie.infoq.cn/article/b48d819cb139416af8a6d4535】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论