今天是第三章:函数
开篇的函数确实很长,虽然命名还较得体,但总不能让人瞻前顾后。另外,其中还有较多重复的代码。
进行重构以后,把细节隐藏起来,让骨骼框架先展示出来确实能让逻辑更清晰。
3.1 短小:
看了开篇的例子,让函数保持短小精干的风格,对大家来说应该是没有异议的。
就好像英语单词,短的总是比长的好记。同样,小函数要表达的意思肯定比长函数要清晰。
小函数只做一件事,能依序把你带到下一个函数,不需要前后对照就能一目了然。
3.2 只做一件事:
函数无非完成特定的功能,即“要到达什么目的,就需要做什么”。如果能一言以蔽之,那函数就在同一抽象层上只做一件事。
3.3 每个函数一个抽象层级:
自顶向下,让代码读起来是一系列的TO起头段落。
3.4 switch 语句
switch 语句大多数时候都有问题,应尽量避免使用。参考 Replace Conditional with Polymorphism, Replace Conditional with Visitor。
3.5 使用描述性的名称:
别害怕花时间取名字。长而具有描述性的名称比短而令人费解的名称好。保持一致的命名方式更能让代码整洁。
3.6 函数参数:
参数能少则一定要少,过多的参数让阅读、理解、测试都变得困难。
3.6.1 一元函数的普遍形式:
询问、指令、事件几种形式,但要谨慎的命名。
3.6.2 标识参数:
标识参数丑陋不堪,应该将该函数一分为二,因为该函数做了不止一件事。
3.6.3 二元函数:
除非必要不要编写二元函数,二元函数的参数之间需要自然的组合或者自然的排序。
3.6.4 三元函数:
编写三元参数前一定要想清楚。
3.6.5 参数对象:
当函数的参数多余一个并且其中一些参数具有相关性时,可以将它们封装成类。参考Introduce Parameter Object, Preserve Whole Object。
3.6.6 参数列表:
可变参数和类型为List的单个参数一样,并不会增加参数的个数。
3.6.7 动词与关键字:
一元函数的函数和参数应当形成非常良好的动词/名词对形式。而其它函数可以将参数名称编码成函数名以减轻记忆参数顺序的负担。
3.7 无副作用:
注意函数中被隐藏起来的事:时序性耦合、顺序依赖等。同时应避免使用输出参数。犹记以前写Windows程序时,老觉得输出参数很别扭,必须要阅读MSDN才知道API如何使用。
3.8 分割指令与询问:
函数做什么与回答什么,二者要进行分离,不要同时进行,否则会导致混乱。参考Separate Query from Modifier。
3.9 使用异常代替返回错误码:
使用异常能将错误处理代码从主代码路径中分离出来,让逻辑更加清晰。参考Replace Error Code with Exception。
3.9.1 抽取Try/Catch 代码块
3.9.2 错误处理就是一件事:
处理错误的函数不该做其它的事。
3.9.3 Erro.java 依赖磁铁:
错误码暗示存在某个类或枚举定义了所有错误码,对它们的修改导致重新编译和部署。
3.10 别重复自己:
重复在计算机各个领域都会出现,因此避免不需要的重复可以极大的消除邪恶的根源。
3.11 结构化编程:
保持函数短小,偶尔出现的return、break或continue语句没有坏处。避免使用goto语句。
3.12 如何写出这样的函数:
最开始也很纳闷,如何才能将代码写得漂亮。后来发现代码是需要打磨的,不管多么厉害的程序员,一开始也不可能面面俱到,而是通过各种方法进行持续改进,才能使代码日臻完善。
3.13 小结:
编程艺术是且一直就是语言设计的艺术。短小的函数、良好的命名以及合适的归置,都是为了更好的把系统当做故事来讲。