代码规范之函数如何命名
⼀.常见函数命名风格
  ⽬前来说,最常见的函数命名主要有两种风格:驼峰命名和帕斯卡命名。
驼峰命名:多个单词组成⼀个名称时,第⼀个单词全部⼩写,后⾯单词⾸字母⼤写;如:
1public void setUserName(String userName);
帕斯卡命名:多个单词组成⼀个名称时,每个单词的⾸字母⼤写;
1public void SetUserName(String userName);
  两种命名风格都是ok的,但要保证⼀点,对于⼀个团队或者⼀个项⽬,需要根据语⾔本⾝的推荐命名⽅式做好约定。⽐如java⼀般都采取驼峰命名,C#采取帕斯卡命名。
⼆. 函数命名最⾼境界
  我们通常说:天下武功,唯快不破。那么对于函数命名来说最⾼境界是什么呢?我认为是:见字如⾯,顾名思义,就是看到函数的名字就知道这个函数具体做了哪些事情。
  ⽐如上⾯的函数:
1public void setUserName(String userName);
  但是下⾯这个函数命名就不是⼀个好的命名:
1public String addCharacter(String originString, char ch);
  这个函数,⼀咋看,还不错,从函数字⾯意思看是给某个字符串添加⼀个字符。但是到底是在原有字符串⾸部添加,还是在原有字符串末尾追加呢?亦或是在某个固定位置插⼊呢?从函数名字完全看不出来这个函数的真正意图,只能继续往下读这个函数的具体实现才知道。
  ⽽下⾯这⼏个名字就⽐上⾯要好得多:
1 2public String appendCharacter(String originString, char ch);    // 追加到末尾
public String insertCharacter(String originString, char ch, int insertPosition); // 插⼊指定位置
三. 函数命名最佳实践
1)要领1:动词选取要精准
  通常来说,动词决定了⼀个函数要采取什么"动作"。动词取的好,⼀个函数名字已经成功了80%。  常⽤动词表:
类别单词
添加/插⼊/创建/初始化/加载add、append、insert、create、initialize、load
删除/销毁delete、remove、destroy、drop
打开/开始/启动open、start
关闭/停⽌close、stop
获取/读取/查/查询get、fetch、acquire、read、search、find、query 设置/重置/放⼊/写⼊/释放/刷新set、reset、put、write、release、refresh
设置/重置/放⼊/写⼊/释放/刷新set、reset、put、write、release、refresh
发送/推送send、push
接收/拉取receive、pull
提交/撤销/取消submit、cancel
收集/采集/选取/选择collect、pick、select
提取/解析sub、extract、parse
编码/解码encode、decode
填充/打包/压缩fill、pack、compress
清空/拆包/解压flush、clear、unpack、decompress
增加/减少increase、decrease、reduce
分隔/拼接split、join、concat
过滤/校验/检测filter、valid、check
  动词决定了函数的具体动作,⽽名词决定了函数具体的操作对象,对于名词,尽量使⽤领域词汇,不要使⽤⽣僻或者⼤家很少使⽤的词语。
2)要领2:名词使⽤领域词汇
  举个例⼦:集合的容量通常⽤capacity、集合实际元素个数⽤size、字符串长度⽤length,这种就遵循⼤家的使⽤习惯,不要⽤size去形如字符串的长度。
  再⽐如,假如使⽤到建造者模式,那么通常会⽤build作为函数名字,这个时候就不要另辟蹊径,⽤create来作为函数名字,使⽤⼤家约定俗成的命名习惯更容易让你的代码被别⼈读懂。
  常⽤名词表:
类别单词
容量/⼤⼩/长度capacity、size、length
实例/上下⽂instance、context
配置config、settings
头部/前⾯/前⼀个/第⼀个header、front、previous、first
尾部/后⾯/后⼀个/最后⼀个tail、back、next、last
区间/区域/某⼀部分/范围/规模range、interval、region、area、section、scope、scale
缓存/缓冲/会话cache、buffer、session
本地/局部/全局local、global
成员/元素member、element
菜单/列表menu、list
源/⽬标source、destination、target
3)要领3:函数取名最忌讳"名不副实"
  函数取名最忌讳的是"名不副实",举个例⼦,假如有个Cache类,⾥⾯有个函数判断key是否过期:
1 2public boolean isExpired(String key) {        // 当前时间戳
2 3 4 5 6 7 8 9 10 11 12 13        // 当前时间戳
long curTimestamp = wUnixTime();
// 获取key的存⼊时间戳
long storeTimestamp = getStoreTimestamp(key);
if(curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {            // 注意这个地⽅的delete是个隐藏逻辑
delete(key);
return true;
false是什么函数}
return false;
}
  上⾯这个函数从函数字⾯意思看是判断key是否过期,但是!!它居然在函数⾥⾯隐藏了⼀段特殊逻辑:如果过期则删除掉key。这个就是典型的"名不副实",这个是最忌讳的,会给后续的开发⼈员留下"巨坑"。
  有两种⽅式去优化这段代码:
⽅式⼀:将隐藏逻辑去掉
1 2 3 4 5 6 7 8 9 10 11
public boolean isExpired(String key) {
// 当前时间戳
long curTimestamp = wUnixTime();
// 获取key的存⼊时间戳
long storeTimestamp = getStoreTimestamp(key);
if(curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {            return true;
}
return false;
}
⽅式⼆:改变函数名字
1 2 3 4 5 6
7 8 9 10 11public int deleteIfExpired(String key) {
// 当前时间戳
long curTimestamp = wUnixTime();
// 获取key的存⼊时间戳
long storeTimestamp = getStoreTimestamp(key);
if(curTimestamp - storeTimestamp > MAX_EXPIRE_SECONDS) {            return delete(key);
}
return0;
}
4)要领4:多查询条件的函数名字谨慎使⽤介词by
  我们平时在写查询接⼝时,假如有多个查询参数怎么办?每个通过by⼀起连接依赖?No!这绝对不是明智的⽅式。假如⼀开始产品的需求是通过学⽣姓名查询学⽣信息,写出来的可能是这样的函数:
1public List<Student> getByName(String name);
  然后突然⼜有⼀天产品提出了新的需求,希望同时可以通过姓名和电话号码来查询学⽣信息,那么函数可能变成这样了:
1public List<Student> getByNameAndMobile(String name, String mobile);
  接着,没过多久,产品⼜希望根据学⽣年龄来查询学⽣信息,那么函数可能变成这样了:
1public List<Student> getByNameAndMobileAndAge(String name, String mobile, int age);
  如果这样来给函数命名,那么你的噩梦⼤门即将打开。
  通常⽐较好的做法是:
如果是通过主键id来查询,那么可以通过by来连接查询信息,⽐如:
1public Student getByStudentId(long studentId);
如果是通过其他属性来查询,并且未来会存在多个组合查询的可能性,建议进⾏封装,⽐如:
1public List<Student> getStudents(StudentSearchParam searchParam);
  最后,建议⼤家平时在写代码过程中,不要怕在函数命名上耗费时间,⼀个好的函数命名在后期会⼤⼤减少你代码重构的成本,争取对函数命名做到"见字如⾯"~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。