代码编写的参考规则-方法篇
简言:在写代码的过程中,我总是会遇到一些复杂的业务,在编写代码时逻辑清晰,一个方法足以写完。但写完后阅读、维护和修改代码时,会很难寻找到相应的代码并修改。这说明我的代码可读性比较低,遵循这些规范,我的代码可读性大大提高了。所以我想分享给更多有这个疑惑的人,如果有什么更好的规则方法,欢迎随时讨论。
1.短小
每个方法应该只有两三行、四行长,并且每个方法一目了然,都只做一件事,并且每个方法都依序把你带到下一个方法。
代码块和缩进,判断语句中的代码应该只有一行,(前提是方法的名称具有说明性的描述)。所以,方法的缩进层级不该多于1层或者2层,这样的方法易于阅读和理解,不但能保持方法短小,还能增加文档价值。
2.只做一件事
方法应该做一件事,做好这件事,只做这一件事。 编写方法是为了把大概念拆分为另一个抽象层上的一系列步骤。所以方法是否是只做了一件事,就看该方法内的代码是否是同一抽象层的。还有一个方法就是看看能否再拆出一个方法,该方法不仅只是单纯地重新诠释其实现。
3.每个方法一个抽象层级(写方法的思维重点)
方法中混杂不同抽象层级,往往让人迷惑。读者可能无法判断某个表达式是基础概念还是细节。一旦细节与基础概念混杂,更多的细节就会在方法中纠缠起来。
自顶向下读代码:向下规则
我们想要让每个方法后面都跟着位于下一抽象层级的方法,这样在查看方法列表时,就可以跟着抽象的层级向下阅读了,这就叫向下规则。
例:最高层:今天要炒菜做饭。下一层:做饭要先煮饭再炒菜。下一层:煮饭要先打米淘米再放进电饭锅,炒菜要切菜开火烧油再翻炒。。。。。。
不过程序员往往很难遵循这条规则,但是这是保持方法短小,确保只做一件事的要诀,让代码读起来是一系列自顶向下的内容。
4.switch语句
写出短小switch语句很难(包括ifelse),需要确保每个switch都埋藏在较低的抽象层级,并且永不重复。但我们可以利用多态来实现这一点,例如将switch埋藏在抽象工厂下,使用接口多态的接收调用。
5.使用描述性的名称
方法越短小,功能越集中,就越便于取个好名字。
好处:能理清你关于模块的设计思路,并帮你改进。命名方式需要保持一致,使用与模块名一脉相承的短语、名词和动词给方法命名。
5.1 别害怕长名称
长而具有描述性的名称,比短而令人费解的名称好。比描述性长注释好。
5.2 别害怕花时间取名字
尝试不同名称,去测试阅读效果,找到最具有描述性的那一个为止。
6.方法的输入参数
方法的输入参数越少越好,应该尽量避免三个及其以上的参数,除非有足够特殊的理由。
原因:参数概念太多,每次看都需要翻译,并且会导致更难测试。
6.1 一元方法的普遍形式(传入单个参数)
向方法传入单个参数,有两种极普遍的理由:一是 是否存在,二是将参数转换为其他类型。还有一种虽然不普遍但是非常有用的单参数方法形式,那就是事件(event)。
这种形式中,有输入参数但是没有输出参数。程序将方法看作是一个事件。(使用时应该小心,让读者清楚的了解它是一个事件,谨慎选用名称和语境)
6.2 布尔值输入参数
一个方法的入参如果是一个布尔值,会导致代码的可读性大大降低。
解决方法:拆解为两个方法,true时一个方法,false时一个方法。
6.3 二元方法
有两个参数的方法比一元方法难懂,重点体现在两个参数存在排序问题,并且会存在传递的参数你需要忽略掉才能看明白的情况(比如传入OutputStream对象)所以可以想办法将二元方法转换为一元方法。
6.4 三元方法
排序,思考,忽略的问题都会加倍体现。
6.5 参数对象
如果方法看来需要两个,三个以上的参数,那就说明有些参数应该封装为类了。
6.6 参数列表
有时,我们需要传入数量可变的参数集合(Object… args),其实这也只算是一个参数,相当于是传递的是一个列表。
setNameList(Object... args) 相当于 setNameList(List<Object> argList)
6.7 动词与关键字
给方法起个好名字,能较好解释方法意图,以及参数的顺序和意图,对于一元方法,方法和参数应该形成好的动词/名词对形式 。
比如 writeField(name); 他告诉我们这个name要被写,并且这个name是一个Field。
7.尽量避免使用输出参数
有些偶然的时序性耦合以及顺序依赖,导致有参数或全局变量的改变不会达到我们预期,这都是违反方法只做一件事的原则而导致的。
输出参数:普遍而言,应该避免使用输出参数,因为面向对象语言中,对输出参数的大部分需求已经消失了。如果方法必须要修改某种状态,就修改所属对象的状态吧。
8.将业务与IF分开
方法要么做什么事,要么回答什么事,如果两者情况一起做,就会导致混乱。
比如一个方法如果设置成功就返回true,这样会导致读起来会让人容易误解,应该分开为是否设置成功和设置两个方法。
9.使用异常替代返回错误码
如果从指令式方法返回错误码,会导致更深层次的嵌套结构,使用异常来代替返回错误码,错误处理代码就能从主代码中分离出来,得到简化。
9.1 try/catch代码的代码块需要抽离
最好把try和catch代码块的主体部分抽离出来,另外形成方法,这样看起来会更美观,利于理解和修改。
9.2 错误处理只处理错误
方法应该只做一件事,而错误处理就是一件事,因此处理错误的方法前后都不该做其他事。
9.3 error.java 依赖磁铁
如果使用某个类或者是枚举来定义所有错误码,修改后会导致其他类都需要重新编译和部署,这样的类就是一块依赖磁铁,如果使用异常来代替错误码,新异常就可以从异常类派生出来,无需重新编译或部署。
10.消除重复(DRY原则)
消除掉重复的代码,会让整个模块的可读性因为重复的消除而得到提升。自从子程序发明以来,软件开发领域的所有创新都是在不断尝试去消灭重复代码。
11.写在最后
1.不要担心写不出这样的好代码,千里之行始于足下,先去做,再去打磨,渐渐就会变成这样的代码,连uncle Bob都做不到一次到位,你为什么纠结呢。
2.编程艺术是且一直是语言设计的艺术。大师级程序员把系统当故事来讲,而不是当做程序来写,所以写方法时可以多用一下故事的思路去想方法实现,可能对你有帮助哦。
3.我是喵煞,如果文章对你有帮助的话可以点赞收藏哦。(关注也可以点一下的其实)