函数是所有程序中的第一组代码。
3.1 短小
函数的第一条规则是要短小。第二条规则是还要更短小。
代码块和缩进
if语句、else语句、while语句等,其中的代码块应该只占一行,该行大抵应该是一个函数调用语句。
函数不应该大到足以容纳嵌套结构。
3.2 只做一件事
函数应该做一件事。做好这件事。只做这一件事。
要判断函数是否不止做了一件事,就是看它是否能再拆出一个函数,该函数不仅只是单纯地重新诠释其实现。
函数中的区段
只做一件事的函数无法被合理地划分为多个区段。
3.3 每个函数一个抽象层级
要确保函数只做一件事,函数中的语句就要在同一抽象层级上。
自顶向下读代码:向下规则
我们想要让代码拥有自顶向下的阅读顺序。
程序就像是一系列TO起头的段落,每一段都描述当前抽象层级,并引用位于下一层级的后续TO起头段落。
3.4 switch语句
写出短小的switch语句很难。
该问题的解决方案是将switch语句埋藏到抽象工厂底下,不让任何人看到。
3.5 使用具有描述性的名称
函数越短小,功能越集中,就越便于起个好名字。
别害怕长名称。长而具有描述性的名称,要比短而令人费解的名称好。长而具有描述性的名称,要比描述性的长注释好。
别害怕花时间起名字。
选择描述性的名称能理清你关于模块的设计思路,并帮你改进之。
命名方式要保持一致。
3.6 函数参数
最理想的参数数量是0,其次是1,再次是2,应尽量避免3.
参数不易对付。
从测试的角度看,参数甚至更叫人为难。
输出参数比输入参数还要难以理解。
与没有参数相比,只有一个输入参数算是第二好的做法。
3.6.1 单参数函数的普遍形式
向函数传入单个参数有两种极普遍的理由。你也许会问关于那个参数的问题。有可能是操作该参数,将其转换为其他的东西,再输出之。
还要一种虽不那么普遍但仍极有用的单参数函数形式,那就是事件。在这种形式中,有输入参数而无输出参数。程序将函数看作是一个事件,使用该参数修改系统状态。
尽量避免编写不遵循这些形式的单参数函数。
3.6.2 标识参数
标识参数丑陋不堪。向函数中传入布尔值简直就是骇人听闻的做法。
3.6.3 双参数函数
有两个参数的函数要比单参数函数难懂。
当然,有些时候两个参数正好。
3.6.4 三参数函数
有三个参数的函数比双参数函数难懂得多。
3.6.5 参数对象
如果函数看起来需要2个、3个或3个以上得参数,就说明其中一些参数应该封装为类了。
3.6.6 参数列表
有可变参数的函数可能是单参数、双参数甚至三参数的。超过这个数量就可能要犯错了。
3.6.7 动词与关键词
给函数起个好名字,能较好地理解函数的意图,以及参数的顺序和意图。对于单参数函数,函数和参数应当形成一种非常良好的动词/名词对形式。
3.7 无副作用
副作用是一种谎言。副作用会导致古怪的时序性耦合及顺序依赖。
输出参数
普遍而言,应避免使用输出参数。如果函数必须要修改某种状态,就修改所属对象的状态吧。
3.8 分隔指令与询问
函数要么做什么事,要么回答什么事,但二者不可得兼。函数应该修改所属对象的状态,或者返回该对象的有关信息。
3.9 使用异常替代返回错误码
从指令式函数返回错误码略微违反了指令与询问分隔的规则。
如果使用异常替代返回错误码,错误处理代码就能从主路径代码中分离出来,从而得到简化。
3.9.1 抽离try/catch代码块
最好把try和catch代码块的主体部分抽离出来,另外形成函数。
3.9.2 错误处理就是一件事
函数应该只做一件事。错误处理就是一件事。
3.9.3 Error.java依赖磁铁
使用异常代替错误码,新异常就可以从异常类派生出来,而无须重新编译或重新部署。
3.10 别重复自己
重复可能是软件中一切邪恶的根源。许多原则与实践规则都是为了控制与消除重复而创建的。
3.11 结构化编程
只要函数保持短小,偶尔出现的return、break或continue语句没有坏处,甚至比单入单出原则更具有表达力。
3.12 如何写出这样的函数
写代码和写别的东西很像。在写论文或文章时,你先想什么就写什么,然后再打磨它。初稿也许粗陋无序,你可以对其斟酌推敲,直至达到你心目中的样子。
3.13 小结
每个系统都是使用某种领域特定语言搭建的,而这种语言是程序员设计来描述那个系统的。
大师级程序员把系统当作故事来讲,而不是当作程序来写。
真正的目标在于讲述系统的故事,而你编写的函数必须干净利落地拼装到一起,形成一种精确而清晰的语言,帮助你讲故事。