基于三件事,学习Spring源码、阅读同事之前的代码、读《重构 改善既有代码的设计》意识到命名,是代码能否阅读的重要保证,而且这种对阅读理解的帮助是注释远不能替代的,利用这个机会重新学习下命名规范,如有错误之处恳请各位大佬指出,不胜感激。
项目名称
全部小写,多个单词中划线分隔"-",eg spring-cloud
包名
全部小写,点分隔符之间有且仅有一个自然语义的英文单词或者多个单词自然连接到一块(如 springframework,deepspace不需要使用任何分割)。
包名统一使用单数形式,类名中有复数含义,则类名中可以使用复数形式。
包名的构成可以分为以下几四部分【前缀】【发起者名】【项目名】【模块名】。常见的前缀可以分为以下几种:
类命名
阿里开发规范要求 类名使用UpperCamelCase风格,必须遵从驼峰形式,但是领域模型命名规约除外,DO/BO/DTO/VO等。
类名通常使用名词或名词短语,此外还可以使用形容词或形容词短语,如Cloneable,Callable等,表示实现该接口的类具有某种功能和能力。对于测试类型,以它要测试的类开头,以Test结尾。
对于一些特殊特有名词缩写也可以使用全大写命名,比如XMLHttpRequest。对于特殊的缩写,原则是统一即可。
阿里开发规范中对类的一些要求
1、杜绝完全不规范的缩写,避免望文不知义
eg: condition “缩写”命名成condi,严重降低了代码的可阅读性
2、为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意
正例:从远程仓库拉取代码的类命名为PullCodeFromRemoteRepository。
反例:变量int a; 的随意命名方式。
3、接口类中的方法和属性不要加任何修饰符号(public也不要加),保持代码的简洁性,并加上有效的Javadoc注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是与接口方法相关,并且是整个应用的基础常量。
正例:接口方法签名:voidf();接口基础常量表示:StringCOMPANY= "alibaba";
反例:接口方法定义:publicabstractvoidf();
说明:JDK8中接口允许有默认实现,那么这个default方法,是对所有实现类都有价值的默认实现。
4、接口和实现类的命名有两套规则:
1)【强制】对于Service和DAO类,基于SOA的理念,暴露出来的服务一定是接口,内部的实现类用Impl的后缀与接口区别。
正例:CacheServiceImpl实现CacheService接口。
2)【推荐】如果是形容能力的接口名称,取对应的形容词做接口名(通常是–able的形式)
正例:AbstractTranslator实现Translatable。
5、枚举类名建议带上Enum后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有
正例:枚举名字为ProcessStatusEnum的成员名称:SUCCESS/ UNKOWN_REASON。
6、分层领域模型规约:
DO( Data Object):与数据库表结构一一对应
TO(Transfer Object):数据传输对象,对象内容从三方获取
DTO( Data Transfer Object):数据传输对象,通过DAO层向上传输数据源对象。
BO( Business Object):业务对象。 由Service层输出的封装业务逻辑的对象。
AO( Application Object):系统级对象
VO( View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。
Query:数据查询对象,各层接收上层的查询请求。 注意超过5个参数的查询封装,禁止使用Map类来传输。
Param: DAO方法内,封装参数
7、领域模型命名规约
1)数据对象:xxxDO,xxx即为数据表名。
2)数据传输对象:xxxDTO,xxx为业务领域相关的名称。
3)展示对象:xxxVO,xxx一般为网页名称。
4)POJO是DO/DTO/BO/VO的统称,禁止命名成xxxPOJO。
属性 | 约束 | 例子 |
抽象类 | Abstract或者Base开头 | AbstractStudentService |
枚举类 | Enum作为后缀 | GenderEnum |
工具类 | Utils作为后缀 | StringUtils |
异常类 | Exception结尾 | RuntimeException |
接口实现类 | 接口名+Impl | UserServiceImpl |
领域模型相关 | DO/DTO/BO/VO | UserVO |
设计模式相关 | 命名中体现出具体模式 | BeanFactory,MapperBuilder |
处理特定功能 | Handler,Validator | 表示处理器,校验器等 ConstraintValidator |
测试类 | Test结尾 | UserServiceTest,表示用来测试UserService |
方法命名
方法lowerCamelCase,首字小写,往后的每个单词首字母都要大写。
方法命名一般为动词或动词短语,与参数或参数名共同组成动宾短语,即动词 + 名词。一个好的函数名一般能通过名字直接获知该函数实现什么样的功能。
阿里开发手册推荐
Service/DAO层方法命名规约
1)获取单个对象的方法用get做前缀。
2)获取多个对象的方法用list做前缀。
3)获取统计值的方法用count做前缀。
4)插入的方法用save/insert做前缀。
5)删除的方法用remove/delete做前缀。
6)修改的方法用update做前缀。
数据处理相关
前缀名 | 意义 |
create | 创建 |
delete | 删除 |
add、insert、append、put | 创建/添加,创建的对象属于某个集合 |
remove | 删除/移除,移除的对象属于某个集合 |
get | 单个对象获取 |
find、query、select、list | 获取多个对象 |
load | 读取 |
fetch | 远程读取 |
set | 设置 |
modify | 修改对象 |
update | 更新对象 |
save、store、commit、apply、submit | 保存 |
逻辑处理
前缀名 | 意义 |
from | 从既有某物新建,或者从其他的数据新建 |
to | 转换 |
is | 对象能否符合期待要求 |
can | 对象能否执行期待动作 |
should | 调用方是否应该执行某个命令 |
has | 对象是否持有需要的数据和属性 |
needs | 调用方是否需要执行某个命令或方法 |
ensure、validate | 检查是否正确,不是抛出异常或者返回error code |
prepare | 处理逻辑前的准备 |
calculate | 数值计算 |
do | 执行某个过程 |
dispatch | 判断程序流程转向 |
parse | 解析 |
build | 构建 |
merge | 合并 |
split | 分割 |
变量&常量命名
通用命名
1、尽量不要使用拼音;杜绝拼音和英文混用。对于一些通用的表示或者难以用英文描述的可以采用拼音,一旦采用拼音就坚决不能和英文混用。
2、命名过程中尽量不要出现特殊的字符,常量除外。
3、尽量不要和jdk或者框架中已存在的类重名,也不能使用java中的关键字命名。
4、妙用介词,如for(可以用同音的4代替), to(可用同音的2代替), from, with,of等。如类名采用User4RedisDO,方法名getUserInfoFromRedis,convertJson2Map等。
变量包括成员变量和局部变量。采用lowerCamelCase,首字小写,往后的每个单词首字母都要大写。变量命名时,尽量简短且能清楚的表达变量的作用,命名体现具体的业务含义即可。
1.代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。
反例:_name/__name/$Object/name_/name$/Object$
2.代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。
说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式也要避免采用。
3、中括号是数组类型的一部分,数组定义如下:String[]args;
4、POJO类中布尔类型的变量,都不要加is,否则部分框架解析会引起序列化错误。
常量命名
一般采用全部大写(作为方法参数时除外),单词间用下划线分割。
常量是在作用域内保持不变的值,一般使用final进行修饰。一般分为三种,全局常量(public static final修饰),类内常量(private static final 修饰)以及局部常量(方法内,或者参数中的常量),局部常量比较特殊,通常采用小驼峰命名即可。
常量一般都有自己的业务含义,不要害怕长度过长而进行省略或者缩写。如,用户消息缓存过期时间的表示,那种方式更佳清晰,交给你来评判。
1、不允许任何魔法值(即未经定义的常量)直接出现在代码中。
2、long或者Long初始赋值时,使用大写的L,不能是小写的l,小写容易跟数字1混淆,造成误解。
3、不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。
4、常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量。
1)跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下。
2)应用内共享常量:放置在一方库中,通常是modules中的constant目录下。
反例:易懂变量也要统一定义成应用内共享常量,两位攻城师在两个类中分别定义了表示“是”的变量:
A中:publicstaticfinalStringYES="yes";
类B中:publicstaticfinalStringYES= "y";
A.YES.equals(B.YES),预期是true,但实际返回为false,导致线上问题。
3)子工程内部共享常量:即在当前子工程的constant目录下。
4)包内共享常量:即在当前包下单独的constant目录下。
5)类内共享常量:直接在类内部privatestaticfinal定义。
5、如果变量值仅在一个范围内变化,且带有名称之外的延伸属性,定义为枚举类。下面正例中的数字就是延伸信息,表示星期几。
总结
命名在提高代码的阅读性发挥着极其重要作用的价值,良好的命名提高代码的可读性以及可维护性,致力于写更好的代码,为此不断努力!
参考文档