掘金 后端 ( ) • 2024-06-26 10:58

命名的技巧

这部分内容主要通过正例和反例的形式来讲述,让大家充分体会到运用这些技巧的魅力。

  1. 名副其实

以书中的一段代码举例:

public List<int[]> getThem() {
    List<int[]> list1 = new ArrayList<int[]>();
    for (int[] x : theList) {
        if (x[0] == 4) {
            list1.add(x);
        }
    }
    
    return list1;
}

这段代码乍一看,没有啥含义,但是如果你在开发的是一款gameBoard的扫雷游戏,这个方法瞬间就有了意义。

public List<int[]> getFlaggedCells() {
    List<int[]> flaggedCells = new ArrayList<int[]>();
    for (int[] cell : gameBoard) {
        if (cell[STATUS_VALUE] == FLAGGED) {
            flaggedCells.add(cell);
        }
    }

    return flaggedCells;
}

一句话:如果名称需要注释来补充,那就不算是名副其实。

  1. 避免误导

  • 名称上包含错误类型,产生误导。
private String accountList;

private List<String> accountList;

java中List后缀命名的对象在开发者的直觉中都会认为是List对象,如果其它类型的对象也使用这个后缀就很容易引发不可预知的错误判断。

其它容易引起误导的比如,字母l和数字1,字母O和数字0,字母Z和数字2,命名的时候都应避免混在一块。

  • 使用俗语或俚语。
private void chifan();

private void eat();

这种容易理解,取名不要图好玩,需要寓意明确。要做到言道意到,意到言道。

  • 每个概念使用一个词。
private void getChannel();

private void fetchMoney();

private void retrieveAuth();
private void getChannel();

private void getMoney();

private void getAuth();

代码中统一用get来表示获取或者查询,这样是不是更不容易产生歧义呢?使用了三个名称,我们也许就会觉得他们三个方法都属于不同的处理动作。

  • 使用特定问题域的名称。

代码中命名使用特定领域内的名称。比如:

private BillInfo bill;// 账单
private BigDecimal principal;// 本金
private BigDecimal interest;// 利息
  • 添加有意义的语境,不要添加没用的语境。

比如下面的Address类中包含了firstName、lastName、street、houseNumber和city属性,包含了语境。

public class Address {
    private String firstName;// 姓
    private String lastName;// 名
    private String street;// 街道
    private long houseNumber;// 住址编号
    private String city;// 城市
}

如果需要区分邮政编码MAC地址和Web地址,则可以考虑定义PostalAddress、MAC和URI三个类,而不是使用实例化出来的accountAddress和customerAddress之类的命名。

  1. 做有意义的区分

定义个数组拷贝的方法,a1和a2的命名都是没有意义的,方法的可读性也比较差。

public static void copyChars(char a1[], char a2[]) {
    for (int i = 0; i < a1.length; i++) {
        a2[i] = a1[i];
    }
}

修改后,代码变成:

public static void copyChars(char source[], char destination[]) {
    for (int i = 0; i < source.length; i++) {
        destination[i] = source[i];
    }
}

不要冗余废话。如:variable不要出现在变量名中;table不要定义在表名中。

  1. 使用读得出来的名称

比如,很多时候我们可能会用简写或者习惯性命名,如:

private Date genymdhms; // 生成yyyy-MM-DD HH:mm:ss格式的时间戳

虽然也能读懂,但是下面的命名是不是更通用一些呢?

private Date generationTimestamp;

  1. 使用可搜索的名称

这个技巧往往发生在定义常量中,比如:

for (int i = 0; i < 34; i++) {
    s += (t[i] * 4) / 5;
}

如果想要代码里搜索数字4,那可能就会搜出很多内容,但如果像下面一样改造下代码:

int realDaysPerIdealDay = 4;
int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int i = 0; i < NUMBER_OF_TASKS; i++) {
    int realTaskDays = taskEstimate[i] * realDaysPerIdealDay;
    int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
    sum += realTaskWeeks;
}

这样,想要搜索数字4的话就可以直接使用realDaysPerIdealDay这个关键字了。 所以,又有理由不在代码中使用硬编码,需要定义成常量字段了。

  1. 避免使用编码

避免使用编码跟上面用常量字段代替硬编码的概念不同,它是指在阅读代码的过程中,很多无用的编码有时候会干造成不必要的干扰,导致代码理解上的困难,这无疑对解决问题是没有帮助的。 不推荐用法:

private boolean bBusy; // 使用匈牙利标记法加类型的前缀命名

private String m_dsc; // 使用m_前缀标明成员变量

public interface IShapeFactory {}; // 使用I前缀表示接口

推荐用法:

private boolean busy;

private String description;

public interface ShapeFactory {};

额外的编码无助解决问题,纯属多余的负担。带编码的名称通常也不便发音,容易打错。

  1. 类和对象名使用名词或名词短语,方法名使用动词或动词短语

这个技巧大家可以在项目中尝试使用,这样写出来的代码整体可读性会很好,比如:

public class Customer {
    public void consume() {
        System.out.println("正在消费...");
    }
}