本文章难度:『简单』
建议阅读场景:通勤路上
解释:在命名时务必做到能『望文生义』,尽量让自己的代码有『自解释性』
正例:定义整形数组 int[] userArray;
反例:在 main 参数中,使用 String args[]来定义。务必使用String[] args
解释:这样书写便于阅读,一眼就知道是数组;int[] 表示定义一个『int数组』类型,不要理解成『一个存int对象的数组』
在 『MySQL 规约』中的『建表约定』第一条,表达『是与否』的值要采用 is_xxx 的命名方式,因此,需要在诸如mybatis框架
反例:定义为『基本数据类型 Boolean』 isDeleted 的属性,它的方法也是 isDeleted(),RPC 框架在反向解析的时候,『误以为』对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。
解释:这是开发中的一个坑,如果不知道,这个点,很难发现问题。很多时候,我们传入的参数如下:
{ "num":1, "isDeleted":true}但是controller收到isDeleted的却是false;
@Setter@Getterpublic class SystemUserVO extends BaseVO { // 框架误认为这个字段是 deleted private Boolean isDeleted;}这就是因为,在反序列化的时候,框架将isDeleted的值误以为是 deleted。
我们为了不踩此类坑,从一开始就规范字段命名。将所有的Boolean类型都不要加is前缀。
防微杜渐,不管是在生活中,还是在写程序时,都是一个好的原则
反例:com.mycompay.systemUser / com.mycompay.Controller
正例:应用工具类包名为 com.alibaba.ai.util、类名为 MessageUtils(此规则参考 spring 的框架结构)
解释:一点分割一个单词,不要写在一起,com.mycompay.systemUser这种名称,果断拆分成com.mycompay.system.user,不要怕太多单词组成一个包名。如果一开始不这样强制,到后面包名称起名就是一个头疼的东西。
java命名原则:不怕长,怕不清晰。
说明:子类、父类成员变量名相同,即使是 public 类型的变量也是能够通过编译,而局部变量在同一方法内的不同代码块中同名也是合法的,但是要避免使用。对于非 setter/getter 的参数名称也要避免与成员变量名称相同。
// 反例:public class ConfusingName { public int age; public string alibaba; // 非 setter/getter 的参数名称,不允许与本类成员变量同名 public void getData(String alibaba) { if(condition) { final int money = 531; // ... } for (int i = 0; i < 10; i++) { // 在同一方法体中,不允许与其它代码块中的 money 命名相同 final int money = 615; // ... } }}class Son extends ConfusingName { //允许与父类的成员变量名称相同 public int age;}解释:子类,父类成员变量名称相同,相当于是重写了
一句话概括就是:一个类中,属性,参数,变量名称不要重复,类与父类的属性不要重复。
该条原则还是为了代码阅读方便而做的规范。
反例:AbstractClass“缩写”命名成 AbsClass;condition“缩写”命名成 condi,此类随意缩写严重降低了代码的可阅读性。
解释:你懂但是别人不懂。
相信只要做过老代码维护的程序员,很大情况都会碰到各种骚缩写,我们尽量不干这种事情,『能写全称就不要缩写』,如果缩写,必须是『行业统一』的缩写。
即使没有codeview的压力,我们敲代码时,也要时刻反省,自己写的代码会不会被骂。
正例:在 JDK 中,表达原子更新的类名为:AtomicReferenceFieldUpdater。
反例:int a 的随意命名方式。
说明:在jdk的juc的源码中,Doug Lea老爷子写代码,含有大量i k j cnt之类的命名,导致其juc框架可读性极差,我们不要效仿这种命名模式。随便拿ForkJoinPool的一段代码,是不是看着就头疼呢?
final ForkJoinTask<?>[] growArray() { ForkJoinTask<?>[] oldA = array; int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY; if (size > MAXIMUM_QUEUE_CAPACITY) throw new RejectedExecutionException("Queue capacity exceeded"); int oldMask, t, b; ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size]; if (oldA != null && (oldMask = oldA.length - 1) >= 0 && (t = top) - (b = base) > 0) { int mask = size - 1; do { // emulate poll from old array, push to new array ForkJoinTask<?> x; int oldj = ((b & oldMask) << ASHIFT) + ABASE; int j = ((b & mask) << ASHIFT) + ABASE; x = (ForkJoinTask<?>)U.getObjectVolatile(oldA, oldj); if (x != null && U.compareAndSwapObject(oldA, oldj, x, null)) U.putObjectVolatile(a, j, x); } while (++b != t); } return a;}特例:如果你的代码『不会被扩展和维护』,也『绝对不会有人来读』,也『不会被codeview』,或者你想写只能自己看的懂的有『核心竞争力』的代码,使用这种简单的命名方式,也未尝不可。
正例:startTime / workQueue / nameList /TERMINATED_THREAD_COUNT
反例:startedAt/ QueueOfWork / listName /
解释:再次加深印象,命名时,最后一个单词一定是名称。命名的时候,只要你是正常在思考,都不会太离谱!
扩展:建议将通用的常量放在一个常量类文件里,比如
/** * System 字典类型的枚举类 */public interface DictTypeConstants { String USER_TYPE = "user_type"; String COMMON_STATUS = "common_status"; // ========== SYSTEM 模块 ========== String USER_SEX = "system_user_sex"; String OPERATE_TYPE = "system_operate_type"; String LOGIN_TYPE = "system_login_type"; String LOGIN_RESULT = "system_login_result";}说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计理念。
正例:
public class OrderFactory; public class LoginProxy; public class ResourceObserver;解释:还是为了『望文生义』的要求,减少代码理解难度。
正例:接口方法签名 void commit(); 接口基础常量 String COMPANY = "alibaba";
反例:接口方法定义 public abstract void f();
说明:JDK8 中接口允许有默认实现,那么这个 default 方法,是对所有实现类都有价值的默认实现。
解释:
接口变量:默认就是public static final。
接口方法:默认就是public abstract。
大家都知道的,就没必要累赘。『不要重复』也是编程的第一准绳。
例:CacheServiceImpl 实现 CacheService 接口。UserDaoImpl实现UserDao接口。
注意:Manager类不需要有接口定义。
解释:SOA:Service-Oriented Architecture,面向服务架构。服务间只通过接口进行沟通,不关心对方的实现细节。
SOA 的特征(面试常问):
正例:AbstractTranslator 实现 Translatable 接口。
解释:望文生义。
说明:枚举其实就是『特殊的类』,域成员均为常量,且构造方法被默认强制是私有。
public enum ClientTypeEnum { // 全部大写,用下划线隔开 PC_MAC(1), H5(2), PC_WIN(1),ALL(0); private final Integer code;}A) Service/DAO 层方法命名规约
1获取单个对象的方法用 get 做前缀。
2获取多个对象的方法用 list 做前缀,复数形式结尾如:listObjects。
3获取统计值的方法用 count 做前缀。
4插入的方法用 save/insert 做前缀。
5删除的方法用 remove/delete 做前缀。
6修改的方法用 update 做前缀。
B) 领域模型命名规约
1数据对象:xxxDO,xxx 即为数据表名。
2数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
3展示对象:xxxVO,xxx 一般为网页名称。
4 POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
解释:领域模型是一个分析模型,帮助系统分析人员、用户认识现实业务的工具,描述的是业务中涉及到的实体及其相互之间的关系,它是需求分析的产物,与问题域相关。
DO( Data Object):与数据库表结构一一对应,通过DAO层向上传输数据源对象。
DTO( Data Transfer Object):数据传输对象,Service或Manager向外传输的对象。
BO( Business Object):业务对象。由Service层输出的封装业务逻辑的对象。
VO( View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象。
建议做为强制的规约执行
到这里,关于命名风格的规约就已经说完了,纵观这些规则,我们可以得出一个大的原则:
减少代码差异性,便于阅读和沟通
本手册将命名规范放在第一章,正说明了,『命名一致性』的重要程度,万事开头难,在我们项目启动时,专业人士建议第一件事就是,统一命名规范。
非专业的专业人士 原创文章
原创不易请【关注】【点赞】【收藏】
如需转载,请回复说明
| 留言与评论(共有 0 条评论) “” |