3.1 短小
- 函数第一规则短小
- 第二规则短小
- if、else、while中的代码块语句应该只有一行;该行应该是一个函数调用语句,并且名称具有解释函数本身作用的功能;
- 函数不应大到可以容纳嵌套结构,缩进层应该只有一层或者两层;
3.2 只做一件事
- 一件事是指在同一抽象层上的事情;
3.3 每个函数一个抽象层级
- 混乱的函数层级使得基础概念和细节不能清楚区分;
- 混乱导致更加混乱;
- 自顶向下的阅读顺序,函数的下面跟着位于下一层级的函数;
3.4 switch语句
- 使switch语句埋藏在抽象层级,去创建派生实体,实体抽象基类定义一般方法,并且由派生类实现自定义方法;
- 单一权责原则:函数的改变仅有一个理由;
- 开放闭合原则:对扩展开放,对修改闭合;
3.5 使用描述性的名称
- 函数越短小,功能越集中,就越便于取个好名字;
- 长而具有描述性的名称比短而模糊的名称好,比长注释好;
- 命名方式在同一模块中保持一致;
3.6 函数参数
- 最理想的函数参数是零,其次一,而后二,三参数避免
- 函数通过参数输入,返回值输出,不太希望通过参数输出;
3.6.1 一元函数的普遍形式
三种情况:
- 测试参数(输入一个,输出布尔值)
- 对参数进行转换(输入一个,输出一个),即使要使用参数输出也应该转换为输出值
- 事件函数(一个输入,没有输出)
- 使用能区分三种功能的名称
3.6.2 标识参数
- 名称不清晰的形参会误导;
- 形参为布尔值导致函数有两个方向,应分开;
3.6.3 二元参数
- 对于天生就有两个参数,当其存在自然的组合或者自然的顺序时,可以存在
assertEquals(expected,actual)
这样的顺序是经过学习和约定的;- 将二元函数转换成一元函数,例如成为成员函数,或者成员变量;
3.6.4 三元函数
- 避免使用三元函数
3.6.5 参数对象
- 当函数需要传递多个有相互关系的参数时,应该封装成为一个类;
3.6.6 参数列表
3.6.7 动词与关键字
- 给函数起一个好名字,能解释函数意图和参数顺序;
- 函数和参数能够形成动名词队
write(name)
、assertExpectedEqualsActual(expected,actual)
3.7 无副作用
- 坚持只做一件事原则;
- 函数名词体现函数的全部功能;
- 注意时序的耦合性,例如只该在初始化调用的地方仅在该处调用;
- 对于输出参数,在面向对象的编程中,可以利用对象的this指针实现;
3.8 分隔指令与询问
- 函数做什么和回答什么要分开实现
3.9 使用异常代替返回错误码
- 当指令与询问混合时,会导致大量的语句嵌套;因为代码要求立即进行错误处理;但当使用异常时,可以将错误处理从主程序逻辑中分离出来;
3.9.1 抽离Try/Catch代码块
- 将Try代码块中的功能封装成一个函数,这样,此抽象层就只有错误处理功能,主要的逻辑处理在下一抽象层;错误处理和功能实现分隔;
3.9.2 错误处理就是一件事
- 函数只该做一件事,错误也是一件事;
3.9.3 错误码
- 返回错误码代表某处实现了某个枚举或者类;
- 当修改该类或者枚举时,得重新编译和部署;
- 但当使用异常时,新异常可以从异常类派生而来,无需重新编译(开放闭合原则)
3.10 别重复自己
- 重复时软件中一切邪恶的根源;
3.11 结构化编程
- 每个函数,函数中的每个代码块都应该只有一个入口和出口;因此只有一个return语句,循环中没有break和continue;绝对没有goto语句;
- 以上规则吧不是绝对的,对于短小的函数可以使用return、break、continue,比单入单出原则更具有表达力;
3.12 如何写出这样的代码
- 先草稿,后打磨;