软件构建(四)——变量的使用原则

变量的好与坏就在很大程度上取决于它的命名的好坏,在给变量命名的时候需要小心谨慎。本文首先详细讲述构建活动中的基本组成成分,即变量的使用原则,接着再讲述适用于为变量——对象和基本数据——命名的原则。这些原则也适用于类、包、文件及其他的编程实体。

1. 使用变量的原则

1.1 变量初始化原则

不恰当的变量初始化所导致的一系列问题都源于变量的默认初始值与你的预期不同,下面给出一些避免产生初始化错误的建议。

  • 在声明变量的时候初始化
  • 在靠近变量第一次使用的位置初始化它
  • 理想情况下, 在靠近第一次使用变量的位置声明和定义该变量
  • 在可能的情况下使用final或者const关键字
  • 注意计数器和累加器,在下次使用前要重置
  • 在类的构造函数里初始化该类的数据成员
  • 利用编译器的警告信息检查是否使用了未经初始化的变量
  • 在程序开始时初始化工作内

1.2 变量的作用域

关于变量引用局部化的指标:

  • 跨度:衡量一个变量的不同引用点的靠近程度,具体数字为对变量前后引用之间的代码行数
  • 存活时间:一个变量存在期间(被引用的第一条语句至结束引用它的最后一条语句)所跨越的语句总数

尽可能缩短变量的跨度和存活时间,可以减少初始化错误的可能,让自己对的代码有更准确的认识,使代码更具可读性。像全局变量的跨度和存活时间都很长,应尽量避免使用。下面是一些减小作用域的一般原则:

  • 在循环开始之前再去初始化该循环里使用的变量,而不是在该循环所属的子程序的开始处初始化这些变量
  • 直到变量即将被使用时再为其赋值
  • 把相关语句放到一起
  • 把相关语句组提取成单独的子程序
  • 开始时采用最严格的可见性,然后根据需要扩展变量的作用

1.3 变量的使用原则

  • 每个变量只用于单一用途:不要将临时变量如temp用于两种用途
  • 避免让变量具有隐含含义,以下做法都是不可取
    • pageCount表示已打印纸张的数量,如果是-1表示有错误发生
    • bytesWritten表示写入输出文件的字节数,如果取值为负,表示用于输出的磁盘驱动器的号码
  • 确保使用了所有己声明的变量

关于变量的绑定时间,通常来说越晚绑定会有更多的灵活性,但复杂度也会越低。看看下面演示的例子,应酌情选择变量绑定时间:

// 编写代码时绑定:硬编码(使用“神秘数字”)很糟糕,一旦要修改颜色则代码其他地方很难保持一致
titleBar.color = 0xFF;

// 编译时绑定:用具名常量可以增加可读性,还能只修改一处就对所有位置生效
private static final int COLOR_BLUE = 0xFF;
private static final int TITLE_BAR_COLOR = COLOR_BLUE;
titleBar.color = TITLE_BAR_COLOR;

// 运行时绑定:程序运行期间读取,可能从配置文件读取,也可能从注册表读取,这是相对最灵活的方式
titleBar.color = ReadTitleBarColor();

// 此外还有对象实例化时绑定(如每次窗体创建时读取数据),甚至即时绑定(如每次窗体重绘时读取数据)

2. 变量的命名规范

2.1 选择好变量名的注意事项

  • 名字要完全、准确地描述出该变量所代表的事物,这是最重要的命名注意事项
  • 以问题为导向:好记的名字反映的通常都是问题,而不是解决方案,例如表示打印机准备状态,printerReady就比bitFlag要更准确描述问题
  • 最适当的名字长度:建议平均8-20个字符,举个例子numberOfPeopleOnTheUsOlympicTeam太长,ntm太短,numTeamMembers正好
  • 较长的名字适用于很少用到的变量,较短的名字适用于局部变量或循环变量
  • 对位于全局命名空间中的名字加以限定词:用namespace、1g_前缀等等
  • 把限定词放到最后,为变量赋予主要含义的部分应位于最前面:例如revenueTotal要优于totalRevenue。这条规则非常适用于项目内约束以提高一致性
    • 常用的限定词:Total、Sum、Average、Max、Min、Record、Pointer等等
    • Num限定词是个例外,通常customerNum表示下表,而numCustomers表示员工总数。但最好的办法是避免用Num,而改用Count或Total来表示总数,用Index表示下标

下表给出一些名字好坏的对比:

变量用途 描述清晰的好名字 描述不到位的坏名字
支票累计额 runningTotal, checkTotal written, ct, checks, CHKTTL
列车的运行速度 trainVelocity, velocityInMph velt, v tv, train
当前日期 currentDate, todaysDate cd, current, c, date
每页的行数 linesPerPage lpp, lines, l, x, x1, x2

2.2 为特定类型的数据命名

  • 循环下标:i、j、k作为下标是约定俗称的。若循环较长会有多层嵌套,最好用xxxIndex的描述性名字做下标
  • 状态变量:取一个比xxxFlag更好的名字,例如reportType要比statusFlag要更清晰。也建议状态变量采用具名常量或枚举类型来表达
  • 临时变量:取一个比temp更具描述性的名字
  • 布尔变量:done表示某件事是否完成,error表示是否发生错误,found表示是否找到,success表示是否成功。布尔变量的名字要明确反映true或false。此外,要使用肯定的名字,不要取notFound、notSuccessful之类的
  • 常量:根据常量所表示的含义取名,而不是为其数值取名

2.3 应该避免的名字

  • 避免使用令人误解的名字或缩写
  • 避免使用具有相似含义的名字:如input和inputValue,recordNum和numRecords等等
  • 避免使用具有不同含义却又相似名字的变量:如clientRecs和clientReps
  • 避免使用发音相近的名字:如wrap和rap
  • 避免在名字中使用数字
  • 避免在名字中拼错单词
  • 避免使用英语中常常拼错的单词
  • 不要仅靠大小写来区分变量
  • 不要使用与变量含义完全无关的名字
  • 避免在名字中包含易混淆的字符

3. 制定命名规范

命名规则在各种编程语言,乃至各个公司都是不同的,但也有一些比较通用的规范可以注意。限于篇幅本文不阐述变量的命名的规范,下面只提一下为何要制定命名规范:

  • 当多个程序员合作开发一个项目时
  • 当你计划把一个程序转交给另一位程序员来修改和维护的时候(这几乎总是会发生)
  • 当你所在组织中的其他程序员评估你写的程序的时候
  • 当你写的程序规模太大,以致于你无法在脑海里同时了解事情的全貌,而必须分而治之的时候
  • 当你写的程序生命期足够长,长到你可能会在把它搁置几个星期或几个月之后又重新启动有关该程序的工作时
  • 当在一个项目中存在一些不常见的术语,并且你希望在编写代码阶段使用标准的术语或者缩写的时候

不同规范所要求的正式程度也有所不同。通常,一个项目所需的规范正式程度取决于为项目组的人员数量,程序的规模,以及程序预期的生命周期。对于微小的、用完即弃的项目而言,实施严格的规则可能就没什么必要。但对于多人协作的大型项目而言,无论是在开始阶段还是贯穿整个程序的生命周期,正式规范都是成为提高可读性的必不可少的辅助手段。

参考文献:电子工业出版社《代码大全(第2版)》第10、11章

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器