最近软件工程课程强调了一些编码规范,觉得很有必要记录下来;从而在以后的编码过程中养成良好的编码习惯。


命名规范

1 命名基本要求

(1)不能以下划线美元符号开始或结束 (2)类名使用大驼峰(UpperCamelCase)风格 (3)方法名、参数名、成员变量、局部变量都统一使用小驼峰(lowerCamelCase)风格 (4)常量命名全部大写,单词间用下划线隔开 (5)包名统一使用小写

但是,不同语言之间的习惯也有所不同,如Python和Java


2 驼峰命名法

        驼峰命名法近年来越来越流行,在java平台、Microsoft Windows以及许多新的函数库中使用得较多。 驼峰命名法分为小驼峰法和大驼峰法两种。小驼峰法是指第一个单词以小写字母开始,从第二个单词开始以后的每个单词的首字母都采用大写字母。变量名一般用小驼峰法书写。 大驼峰法的第一个单词的首字母也是大写。常用于类名、属性、命名空间等。


3 禁止拼音命名

     (不过,感觉拼音命名还是有一定可取的哈哈哈,英文单词有时反而太长且缩写产生歧义)

public class Pingyin {
    //一、拼音本身不能很好的区分动词和名词,
    //提交类型的实例应该是名词,而对于方法这个场景,“提交”应该是动词。但从拼音明明本身,无法得知是名词还是动词。
    TiJiao tijiao;

    void tiJiao(){
    }
    //二、从可读性来说,拼音的可读性不一定有英文高
    //比如以下场景,对比拼音和英文。拼音很长,阅读不方便,而英文一目了然。
    //获取指定时间后的所有订单
    Object huoQuZhiDingShiJianHuoDeSuoYouDingDan(LocalDateTime time){
        return null;
    }

    Object getOrdersAfter(LocalDateTime time){
        return null;
    }

    //三、拼音无法区分单数和复数
    //返回列表的提交应该是复数,返回单个提交,应该是单数,而拼音无法体现。
    List<TiJiao> huoQuTiJiao(){
        return null;
    }

    TiJiao huoQuTiJiao(){
        return null;
    }

    //对比使用英文单词命名,区分单复数很方便。
    List<TiJiao> getOrders(){
        return null;
    }

    TiJiao getOrder(){
        return null;
    }    
}

4 禁止不规范缩写

        有时候我们想将一些长的命名进行缩写,减少命名长度,但这样会减少可读性。

public class Abbreviation{
//一、不规范的缩写,影响可读性。
//generateId的缩写
void genId(){

}
//startActivity的缩写
void startAct(){

}

//可能是percent的缩写,也可能是personal computer的缩写
private double pc;


//二、通用的缩写,可以使用
//如Tcp
void createTcpConnection() {

}
//dns
private String dnsServer;
//k8s
private String k8sService;

// 专业领域
public void dijkstra() {

}

}

5 足够长以揭示意图, 又不过长难于理解

        虽然第一个方法名将意图表达的很清楚(通过产品id从库存系统获取产品库存),但太过于冗长,在阅读时无法一眼看出方法的具体含义。

        优化:方法的参数名为productId,已经表达了通过产品id获取的含义,所以可以去掉; 产品库存理应从库存系统获取,所以“从库存系统”的限定语也可以删除。

        优化后,方法名表达的含义一目了然。

//通过产品id从库存系统获取产品库存
public void getProductInventoryFromInventorySystemByProductId(String productId) {

}
获取产品库存
public void getProductInventory(String productId) {

}

6 命名拆分

如果不好命名,考虑类/方法职责过多,是否需要拆分重构。

        根据方法名可以得知,该方法需要检查用户是否存在、更新用户、更新缓存、发送邮件给用户,导致命名过长。

public void updateUserBothDBAndCacheThenSendMail() {
// 检查用户是否存在
// 更新用户
// 更新缓存
// 发送邮件给用户
}

进行拆分:(这其实不光是命名规范了,对 对象的合理分析,对类的合理定义也有助于编码)

// 检查用户是否存在
public void isUserExisted() {

}

// 更新用户
public void updateUserInDB() {

}

// 更新缓存
public void updateUserInCache() {

}

// 发送邮件给用户
public void sendNotification() {

}

7 使用有意义的名字

        禁止使用模糊命名,魔法数字!

//(1)当前日期


// 反例
// 无法得知是什么日期
private LocalDate date;

// 正例
//可以一目了然看出这是当前日期
private LocalDate currentDate;


//(2)每页数据条数


// 反例

private int size;

private int lines;

// 正例

private int pageSize;

private int linesPerPage;


//(3)布尔值


// 反例
private boolean flag;

// 正例
private boolean dataReady;


//(4)数值


// 反例
private static final int THREE = 3;

// 正例
private static final int RETRY_TIMES = 3;


//(5)参数


// 反例

public void copyArray(int[] aArray, int[] bArray) {
for (int i = 0; i < aArray.length; i++) {
bArray[i] = aArray[i];
}
}

// 正例

public void copy(int[] source, int[] target) {
for (int sourceIndex = 0; sourceIndex < source.length; sourceIndex++) {
target[sourceIndex] = source[sourceIndex];
}
}

// 反例
public void printScoreDemoOne() {
int[][] scores = new int[10][5];
for (int i = 0; i < scores.length; i++) {
for (int j = 0; j < scores[i].length; j++) {
int score = scores[i][j];
// xxx
}
}
}

// 正例
public void printScoreDemoTwo() {
int[][] scores = new int[10][5];
for (int userIndex = 0; userIndex < scores.length; userIndex++) {
for (int courseIndex = 0; courseIndex < scores[userIndex].length; courseIndex++) {
int score = scores[userIndex][courseIndex];
// xxx
}
}

}

8 范围越大命名越长;范围越小命名越短

        (1)下面代码,定义了用户token所在缓存的命名空间,因为类名只限定了是命名空间,所以我们需要用比较多的限定来限定命名。

public class Namespace {
public static final String USER_TOKEN_CACHE_NAMESPACE = "userToken";
}

        (2)如果有一个UserTokenCache类,已经限定了范围是用户token缓存,这时候进行命名空间声明时,只需要使用namespace即可。

public class UserTokenCache {

private final String namespace = "userToken";

}

        回到这条规则,范围越大,说明对明明本身的限定就越少,所以我们在命名的时候需要加更多的限定语。反之,范围越小,我们就可以使用更小的限定语,作用域越小,产生歧义的可能性就越小。


9 防止名称误导

        编写程序时,应该防止误导性的命名出现。误导性的命名不仅误导他人,也误导自己。 int[] userList = new int[MAXN]; //存储一组用户 如果用userList表示一个用户列表,但他并不是一个List,而是一个数组,那么这就是一个误导性的命名。

        对于List这种有特殊意义的词语,最好在只有该标识符真的是一个List时,才可以在命名中包含它。


10 一致性

        不管我们使用何种规约进行命名,在团队内部一定要达成一致,否则在系统中明明将非常混乱


总结

        不同的企业、团队有各自的编码规范,不同的程序员也有自己的习惯风格..编写出高效、易读、易维护的代码是有点重要的。