文章目录
命名
将代码规范和java面向对象的特性结合起来
将需要判断的内容封装成类的属性,只暴露外部需要的接口,用规范的命名来体现接口的作用,在接口内部实现相应的逻辑即可。
###不要过度依赖IDE提供自动代码提示来进行命名
比如一组账号
使用IDE的代码提示功能所得到的就是accountList
,而accountGroup
则是更符合场景需求的命名,毕竟包纳账号容器的不一定是一个List。
###对于拷贝函数或者说数据迁移函数,一定要通过命名来体现数据的流向
例如copyStr(String str1, String str2)
,调用者除非打开该函数的源码,否则只能通过测试来知道到底哪个是源,哪个是目标。修改后的copyStr(String source, String destination)
###做有意义的命名,命名除了要符合场景,具有场景语意之外,还要避免冗余
比如避免:
Product
,ProductInfo
,ProductData
zork
,theZork
NameString
,Name
等类似的完全没有必要的前缀和后缀。
###命名要保持一致性
函数命名,类命名都要保证前后一致性,比如Controller
,Manager
,Driver
都是很相近的命名,在一个场景里要避免混合使用。
###操作类函数命名要尽量详细一些
add
,insert
,append
都是增加的意思,但是add
是将两个现存值的基础上产生一个新值,而append
,insert
则是新增加到旧集合或者旧容器中,更适合单参的方法。
###使用有意义的前缀或者后缀体现出变量的语境
举个例子:firstName
,lastName
,street
,houseNumber
,city
,state
搁在一起的时候明显是构成了一个地址,但是当在某个地方只有一个state
或者city
时,可能很难推断出他的语境,这时可以添加前缀来体现语境,例如addrFirstName
,addrState
等,但是最好的办法还是建立Address
类。
函数
短小,更短小
函数内容最理想的状态就是每个函数都依序把你带到下一个函数,这就是函数应该到达的短小程度。
每个函数一个抽象层级
函数的步骤应该只涉及在同一抽象层中,当涉及多个抽象层时函数就需要进行拆分了,对于不同抽象层级的步骤,上层调用下层,就像TCP/IP
协议簇的设计原则一样,每层都有自己的分工,上层依赖下层提供的接口,但上层并不用关心下层的内部实现。
自顶向下读代码:向下规则
写代码的时候想想自己的代码这样能不能读懂
函数参数
- 函数参数应该控制在三个及三个以下,当数量超过了标准时,要么是函数需要被拆分,要么是参数需要被封装。
- 不应当向函数中传入
boolean
类型的参数,当必须需要这类参数时,说明函数需要被拆分了,因为传入boolean
参数的函数一是很难从函数名称命名上推断出函数的功能,二是函数内部的功能肯定会因为参数值产生两个分支,所以不如干脆将一个函数写成两个函数。 - 使用二元函数时,看是否能将参数变成一个成员
函数名称应该体现出函数的所有功能,否则会因为时序性耦合导致一些副作用
使用异常替代返回错误码
1. 错误处理代码能从主路径代码中分离出来
例如if(deletePage(page) == ERROR_CODE)
,当返回错误码时就是要求调用者立即处理错误,而不是进行更深层次的嵌套结构。所以尽量使用抛出异常来替代返回错误码这种方式。
并且在try/catch
中,应该将try
和catch
的主体部分抽离出来,另外形成函数。
2. 新异常可以从异常类派生,但返回码需要管理
返回错误码通常是个枚举类,里面定义了所有的错误码
public enum Error {
OK,
INVALID,
NO_SUCH,
SYSTEM_ERROR
...
}
当Error枚举修改时,所有其他的类都需要重新编译和部署,这对Error类造成了负面压力,但是用异常替换错误码时,新异常就可以从异常类派生出来。
格式
概念间垂直方向上的区隔
代码都是从上往下读,从左往右读。每行展现出一个表达式或一个子句,每组代码行展示一条完整的思路。这些思路用空白行区隔开来。要将这种格式发挥到抽掉空白行之后的代码的可读性会大大下降。
###垂直方向上的靠近
紧密相关的代码应该相互靠近。
对象和数据结构
过程式代码难以添加新数据结构,因为要更改所有函数,面向对象代码难以添加新函数,因为必须修改所有类。