命名规范
命名长度
命名的原则以准确达意为目标,其长度以遵循此原则为主,并且是越短越好。
- 对于公认、熟知的词,可以在项目内部统一成缩写
- 对于作用域较小的变量,可以使用较短的命名
- 对于作用域较大的变量,推荐使用可达意的较长的命名
命名上下文
命名时可以根据上下文来简化命名,如在 User 类中,就不需要对类中的成员变量添加 user
前缀,而是直接命名如 name
、password
等名称。
在使用时,开发者也可以借助上下文明确变量的含义。
可读性
可读性指的是不使用特别生僻、难发音的英文单词来命名,同时也不要使用一些无意义、随意搭配的单词。
可搜索性
命名可搜索性指的是,使用 IDE 开发的时候,可以很方便地使用“关键词联想”功能快速补全。
这个原则指的是,最好能在项目、团队内部统一命名方式,如都使用 selectXXX
表示查询,而不是既有 selectXXX
,也有 findXXX
或 queryXXX
等多种命名方式表示查询。
接口、抽象类
对于接口的命名,通常有两种比较常见的方式:一种是接口加前缀 I
表示 Interface,如 IUserService
;另一种是实现类加后缀 Impl
表示 implements,如 UserServiceImpl
。
对于抽象类的命名,也有两种常见的方式:一种是带上前缀 Abstract
表示抽象类,如 AbstractConfig
;另一种是不带前缀。
无论是接口还是抽象类,选择哪个命名方式都可以,最重要的是能在项目内部统一。
注释规范
注释内容
注释的目的是让代码更容易看懂。
注释的内容主要是包括三个方面:做什么、为什么做、怎么做。对于复杂的接口或类,还需要补充“如何用”。
注释多少
注释本身有一定的维护成本,并非越多越好。
类和函数一定要写注释,而且要写得尽可能全面、详细,函数内部的注释要相对少一些,一般可以通过好的命名、提炼函数、解释性变量、总结性注释等方式来提高代码可读性。
代码风格
类和函数的行数
对于函数代码行数的最大限制,网上有一种说法:最好不要超过一个显示屏的垂直高度。
对于类的代码行数的最大限制,有一个间接的判断标准:
- 当一个类的代码读起来比较困难
- 实现某个功能时不知道该用哪个函数
- 想用哪个函数的时候需要找很久
- 只用到一个小功能的时候要引入整个类
一行代码的长度
总体遵循一个原则:一行代码最长不能超过 IDE 显示的宽度。
需要滚动鼠标才能查看一行的全部代码,显然不利于代码的阅读;但是太小的限制也会导致很多稍长点的语句被折成两行。
分隔单元块
对于比较长的函数,如果逻辑上可以分为几个独立的代码块,但是又不方便将这些独立的代码块抽取成小函数的时候,可以使用总结性注释的方式分隔代码块。
除此之外,还可以通过使用空行分隔代码块。如类的成员变量和函数之间、静态成员变量和普通成员变量之间、各函数之间、甚至是各成员变量之间。
类成员的排列顺序
在 Google Java 编程规范中,依赖类按照字母序从小到大排列、类中先写成员变量后写函数、成员变量之间或函数之间先写静态成员变量或函数(按照作用域大小依次排列)。
常用技巧
善于提炼函数
对于逻辑比较复杂的代码,通常是建议提炼出类或者函数,但也避免提炼出的函数只包含两三行代码,以增加阅读成本。
避免函数参数过多
通常函数的参数超过 5 个时候就会影响到代码的可读性,使用起来也不方便。
出现函数参数较多的情况,通常有两个解决办法:根据单一职责原则拆分成多个函数;将函数的参数封装成对象。
勿用函数参数控制逻辑
切勿在函数内部根据函数的参数来控制内部逻辑,如根据 isVip = true
时走 VIP 的逻辑、isVip = false
走非 VIP 的逻辑。
针对于这样情况,通常是根据需求将其拆分成多个函数,拆分之后的函数职责更明确。
函数设计要职责单一
不只是针对类、模块而言,对于函数的设计,更要满足单一职责原则。
移除过深的嵌套
代码嵌套最好不超过两层,超过两层之后就要思考一下是否可以减少嵌套,以避免难以理解和代码缩进过多。
解决代码嵌套过深的方法有以下几种思路:
- 去掉多余的
if
或者else
语句 - 使用编程语言提供的
continue
、break
、return
关键字提前退出嵌套 - 调整执行顺序来减少嵌套
- 将部分嵌套的逻辑封装成函数调用,以此来减少嵌套
- 使用多态来替代
if-else
、switch-case
条件判断
使用解释性变量
使用解释性变量可以提高代码的可读性,常见的情况有以下几种:
- 使用常量取代魔法数字
- 使用解释性变量来解释复杂表达式
函数错误返回
函数的运行结果可以分为两类:正确情况下输出的预期结果,异常(出错)情况下输出的非预期结果。
在异常情况下,函数返回的数据类型非常灵活,可以针对不同的场景和特点选择不同的返回值。
返回错误码
C 语言没有异常这样的语法机制,返回错误码是最常见的出错处理方式。
而 Java、Python 等比较新的编程语言,大部分情况下,都用异常来处理函数出错的情况,极少会用到错误码。
返回 NULL 值
在多数编程语言中,使用 NULL
值表示“不存在”这种语义。
对于查找函数来说,数据不存在并非一种异常情况,是一种正常行为,所以返回表示“不存在”语义的 NULL
值比返回异常更加合理。
返回空对象
返回 NULL
值有各种弊端,对此有一个比较经典的应对策略,那就是应用空对象设计模式。
当函数返回的数据类型是字符串类型或者集合类型的时候,可以用空字符串或空集合替代 NULL
值,来表示不存在的情况。
抛出异常对象
最常用的函数出错处理方式是抛出异常。异常可以将正常逻辑和异常逻辑的处理分离开,这样的代码可读性会更好。
对于抛出的异常对象,通常有以下几种处理方式:
- 直接吞掉,如在捕捉之后只记录日志,不做任何处理
- 原封不动的重新抛出,如在调用的函数外部重新抛出相同的异常
- 包装新的异常重新抛出,如在捕捉之后抛出另一个的异常