代码整洁之道

本书结构

就问你美不美


代码整洁之道


有意义的命名

2.1 介绍

2.2 名副其实

  • 变量和函数或类的名称应该已经答复了大问题,他该告诉你,他为什么会存在,他做什么事,应该怎么用。
  • 如果名称需要注释来补充,那就不算是名副其实。

    以下的代码不能让人一目了然

    1
    2
    3
    4
    List<int[]> flaggedCells = new ArrayList<int[]>(); (1)
    for(int[] cell : gameBoard){
    if(cell[STATUS_VALUE] == FLAGGED){...} (2)
    }

可以更进一步,修改成:

1
2
3
4
List<Cell> flaggedCells = new ArrayList<Cell>();
for(Cell cell : gameBoard ){
if(cell.isFlagged()){...}
}


主要有两点:

  • (1)、将int[]的List换成Cell的List
  • (2)、将状态判断提取成一个函数isFlagged

2.3 避免误导

  • 程序员必须避免留下掩藏代码本意的错误线索,应当避免使用与本意相悖的词。
  • 不要使用hpaixsco作为变量名,因为他们都是UNIX平台或类UNIX平台的专有名词。
  • 不要使用accountList 来指称一组账号,除非他真的是List类型。
  • 不要使用不同之处较小的名称。例如:XYZControllerForEfficientHandingOfStringsXYZControllerForEfficientStorageOfStrings

    误导性名称是最可怕的

    1
    2
    3
    4
    5
    6
    int a = 1;
    if (O == 1) {
    a == 0l;
    }else{
    l = 01;
    }

2.4 做有意义的区分

  • 以数字系列命名(a1、a2、…aN)是依意命名的对立面。这样的名称纯属误导————完全没有提供正确的信息;没有提供导向作者意图的线索。

    例如一下代码:

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

如果将参数名改为sourcedestination,这个函数就会好很多。

  • 废话是另一种没意义的区分。假如你有一个Product类。如果还有一个ProductInfo类和ProductData类,
    虽然他们名称不同,但意思却无区别。info和Data就像a、an、the一样是意义含混的废话。
  • 废话都是冗余。Variable一词永远都不要出现在变量名中。Table一词永远不要出现在表明中。
    nameString会比name好么?难道Name会是浮点数么?

    看下面这种情况:

    1
    2
    3
    getActiveAccount();
    getActiveAccounts();
    getActiveAccountInfo();

 程序员怎么能知道调用哪个呢?如果缺少明确约定,变量 moneyAmountmoney 没有区别,
customerInfocustomer 没有区别,accountDataaccount没有区别,
要区分名称就要以读者能鉴别不同之处的方式来区分。

2.5 使用读的出来的名称

  • 总结下来就是一句,不要自造词,引号使用恰当的英语单词。
1
2
3
4
5
class DtaRcrd102P{
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
}

在看看下面的代码:

1
2
3
4
5
6
class Customer{
private Date generationTimstamp;
private Date modificationTimestamp;
private final String recordId = "102";
}

这样应该不会发生,生成时间戳被设置成明天了,应该不会了吧。

2.6 使用可搜索的名称

  • 不要使用单字母如e或者单数字如3来作为变量名,它是英文中最常用的字母,在每个程序、每段代码中都有可能出现。
  • 名称长短与其作用域大小相对应,比如你就3行代码,你就没必要起很长的变量名,你都可以搜索的到。

2.7 避免使用编码

2.7.1 匈牙利语标记法

  • Fortran语言要求首字符体现出类型。
1
2
// 类型变化时,名称并不变化。
PhoneNumber phoneString;

2.7.2 成员前缀

  • 不必使用m_前缀来标明成员变量。

private String m_dsc;

远不如使用:

private String description;

人们很快会无视前缀(或后缀),只看到名称中有意义的部分。代码读的越多严重就越没有前缀。

2.7.3 接口和实现

  • 一个创建形状的抽象工厂,该工厂是个接口,要用具体类来实现。你如何来命名。
  • IShapeFactory 或者是 ShapeFactory
  • 我喜欢不加修饰的接口,不喜欢 IShapeFactory,前导字母I被滥用到了说好听点是干扰,说难听点根本就是废话的程度。

2.8避免思维映射

  • 一个专业的程序员知道,明确才是王道,专业程序员能善用其能,编写其他人能理解的代码。

2.9类名

  • 类名和对象名应该是名词或名词短语,如 CustomerWikiPageAccountAddressParser 。避免使用 ManagerProcessorDataInfo 这样的类名。
  • 类名不应该是动词

2.10 方法名

  • 方法名应该是动词或动词短语,如 postPaymentdeletePagesave 。属性访问器、修改器和断言应该根据其值命名,并根据Javabean标准加上 get setis 前缀。
    1
    2
    3
    String name = employee.getName();
    customer.setName("Benny");
    if ( payCheck.isPosted() ){ ... }

重载构造器,使用描述了参数的静态工厂方法命名,例如:


Complex fulcrumPoint = Complex.FromReadNumber(23.0);

通常好于:


Complex fulcrumpoint = new Complex(23.0);

2.11 别扮可爱

  • 不要用俗话或俚语。例如,不要使用whack()来表示kill()。别用eatMyshorts()这类与文化紧密相关的词语表示abort()。

2.12 每个概念对应一个词

  • 简单点说不要里面即出现DriverManager又出现Protocol-Controller
    为什么不全用Controler或者Manager,这种名称会让人觉得这两个对象是不同类型的,也分属不同的类。

2.13 别用双关语

  • 在多个类中都有add方法,该方法通过增加或连接两个现存值来获得新值。
  • 假如要写个新类,该类中只有一个方法,将单个参数放到Collection中去,此时如果叫做add的话,
    这样做貌似和其他add方法保持了一致, 但实际上语义不同,应该用insert或者append之类的词来命名才对,
    将该方法命名为add,就是双关语了。

2.13 使用解决方案领域名称

Contents
  1. 1. 本书结构
  2. 2. 有意义的命名
    1. 2.1. 2.1 介绍
    2. 2.2. 2.2 名副其实
    3. 2.3. 2.3 避免误导
    4. 2.4. 2.4 做有意义的区分
    5. 2.5. 2.5 使用读的出来的名称
    6. 2.6. 2.6 使用可搜索的名称
    7. 2.7. 2.7 避免使用编码
      1. 2.7.1. 2.7.1 匈牙利语标记法
      2. 2.7.2. 2.7.2 成员前缀
      3. 2.7.3. 2.7.3 接口和实现
    8. 2.8. 2.8避免思维映射
    9. 2.9. 2.9类名
    10. 2.10. 2.10 方法名
    11. 2.11. 2.11 别扮可爱
    12. 2.12. 2.12 每个概念对应一个词
    13. 2.13. 2.13 别用双关语
    14. 2.14. 2.13 使用解决方案领域名称