成员函数标准
切记:你今天所写的代码可能在今后的数年里仍在使用,而且很有可能由其他人来维护和改进。应尽可能使你的代码“整洁”易懂,因为这会使代码易于维护和改进。
命名成员函数
成员函数的命名应采用完整的英文描述符,大小写混合使用:所有中间单词的第一个字母大写。成员函数名称的第一个单词常常采用一个有强烈动作色彩的动词。
示例:
openAccount() printMailingLabel() save() delete()
这种约定常常使人一看到成员函数的名称就能判断它的功能。虽然这种约定要使开发者多做一些输入的工作,因为函数名常常较长,但是回报是提高代码的可理解性。
命名存取成员函数
在后续章节中,我们将更详细地讨论获取和存放字段值(字段/属性)的存取成员函数。下面将概括一下存取函数的命名约定。 获取函数
获取函数作为一个成员函数,返回一个字段的值。除了布尔字段之外,应采用 get 作为字段的前缀;布尔字段采用 is 作为前缀。
示例:
getFirstName() getAccountNumber() isPersistent() isAtEnd()
遵循这个命名约定,显然,成员函数将返回对象的字段,布尔型的获取函数将返回布尔值“真”或者“假”。这个标准的另一个优点是:它遵循 beans development kit (BDK) 对获取成员函数采用的命名约定 [DES97]。它的一个主要的缺点是 get 是多余的,需要额外的录入工作。
获取函数的另一种命名约定。Has 和 Can
基于正规英文约定的一个可行的取代方法是,用 has 或者 can 来代替布尔型获取函数的 is 前缀。 例如,形如 hasDependents() 和 canPrint() 的获取函数,读起来就发现它们意义更加明确。这种方法存在的问题是 BDK 目前还不支持这种命名方法。可以将 isBurdenedWithDependents() 和 isPrintable() 这些成员函数重新命名。
设置函数
设置函数,也叫变值函数,是可以修改一个字段值的成员函数,。无论何种字段类型,都要在字段名的前面加上 set 前缀。
示例:
setFirstName(String aName)
setAccountNumber(int anAccountNumber) setReasonableGoals(Vector newGoals) setPersistent(boolean isPersistent) setAtEnd(boolean isAtEnd)
按照这种命名约定,显然是一个成员函数设定一个对象的字段值。这个标准的另一个优点是:它遵循 beans development kit (BDK) 对设置函数采用的命名约定 [DES97]。 它的一个主要的缺点是 set 是多余的,需要额外的录入。
命名构造函数
构造函数是在一个对象初次生成时,完成所有必需的初始化的成员函数。构造函数与它所属类的名字总是相同的。例如,类 Customer 的构造函数是 Customer()。注意大小写一致。
示例:
Customer() SavingsAccount() PersistenceBroker()
这个命名约定由 Sun 公司设定,必须严格遵守。
成员函数的可见性
良好的程序设计应该尽可能减小类与类之间耦合,所遵循的经验法则是:尽量限制成员函数的可见性。如果成员函数没必要公有 (public),就定义为保护 (protected);没必要保护 (protected),就定义为私有 (private)。
可见性 public 说明 公有成员函数可被任何其它对象和类的成员函数调用。 正确用法 当该成员函数必须被该函数所在的层次结构之外的其他对象和类在访问时。 当该成员函数提供的行为被它所在类的层次结构内部而非外部需要时。 当该成员函数所提供的行为明确针对定义它的类时。私有成员函数常常是重新分配要素的结果。重新分配要素又叫“重组”,指类内其它成员函数封装某一个特定行为的做法。 protected 被保护的成员函数可被它所在的类或该类的子类的任何成员函数调用。 私有成员函数只可以被该类所在的其它成员函数调用,该类的子类不可以调用。 private 注释成员函数
如何注释一个成员函数常常成为判断函数是否可被理解,进而可维护和可扩展的决定性因素。
成员函数的函数头
每一个 Java 成员函数都应包含某种称之为“成员函数文档”的函数头。这些函数头在源代码的前面,用来记录所有重要的有助于理解函数的信息。 这些信息包含但不仅仅局限于以下内容:
1. 成员函数做什么以及它为什么做这个。通过给一个成员函数加注释,
让别人更加容易判断他们是否可以复用代码。注释出函数为什么做这个可以让其他人更容易将你的代码放到程序的上下文中去。也使
其他人更容易判断是否应该对你的某一段代码加以修改(有可能他要做的修改与你最初为什么要写这一段代码是相互冲突的)。 2. 哪些参数必须传递给一个成员函数。还必须说明,如果带参数,那么什么样的参数必须传给成员函数,以及成员函数将怎样使用它们。这个信息使其他程序员了解应将怎样的信息传递给一个成员函数。在 (第 1.4.2 节“快速浏览 javadoc”) 中讨论的 javadoc @param 标
识便用于该目的。
3. 成员函数返回什么。如果成员函数有返回值,则应注释出来,这样
可以使其他程序员正确地使用返回值/对象。在 (第 1.4.2节“快速浏览 javadoc”) 里讨论的 javadoc @return 标识便用于此目的。 4. 已知的问题。成员函数中的任何突出的问题都应说明,以便让其他
程序开发者了解该成员函数的弱点和难点。如果在一个类的多个成员函数中都存在着同样的问题,那么这个问题应该写在类的说明里。 5. 任何由某个成员函数抛出的异常。应说明成员函数抛出的所有异常,以便使其他程序员明白他们的代码应该捕获些什么。在 (第 1.4.2
节“快速浏览 javadoc”) 中讨论的 javadoc @exception 标识便用于此目的。
6. 可见性决策。如果你觉得你对于一个成员函数可见性的选择会遭到
别人的质疑,例如可能你将一个成员函数设为公共的,但是却没有任何对象调用该成员函数,那么应说明你的决定。这将帮助其他开
发者了解你的想法,使他们不必浪费时间操心考虑你为什么要选择一种有疑问的东西。
7. 成员函数是如何改变对象的。若一个成员函数修改了一个对象,例
如一个银行帐户的成员函数 withdraw() 修改了帐户余额,那么就需要说明。 这种信息必须给出,使其他 Java 程序员能准确地知道
一个成员函数调用将如何影响目标对象。
8. 避免使用含有信息的函数头。比如说作者、电话、创建和修改日期、
单元(或者文件名)的位置,因为这些信息很快就会过时。将版权所有者信息放到单元的最后。例如,读者不会想要翻过两三页诸如
“版权所有”等对理解程序毫无帮助且(或)不提供任何编程信息的文本。避免使用垂直滚动条或者关闭的文本框或对话框,这些东西只会增加视觉干扰,而且较难保持一致。采用一个配置管理工具来保存单元历史。
9. 如何在适当情况下调用成员函数的例子。最简单的确定一段代码如
何工作的方法是看一个例子。考虑包含一到两个如何调用成员函数的例子。 10. 可用的前提条件和后置条件。 前提条件是指一个成员函数可正确运
行的限制条件;后置条件是指一个成员函数执行完以后的属性或声
明 [MEY88]。前提条件和后置条件以多种方式说明了在编写成员函数过程中所做的假设 [AMB98],精确定义了一个成员函数的应用范围。
11. 所有并行事件。对众多程序开发者来说,并行性是一个新而复杂的概念;对有经验的并行性程序开发者来说,并行性也是一个老但却
复杂的课题。最终结果是,如果应用了 Java 的并行编程特性,那么应在程序中详细地将其注释出来。[LEA97] 建议,当一个类既包含了同步也包含了非同步的成员函数时,必须注释出成员函数依赖的执行上下文,尤其是当函数可被无约束访问时。这样可以让其他开发者安全地使用你的成员函数。当一个采用了 Runnable 接口的类的设置函数(即可更新一个字段的成员函数)没有同步时,应说明这样做的理由。 最后,如果覆盖或重载一个成员函数,并且修改了它的同步性时,也应说明理由。
仅当注释增加代码的清晰度时,才应加上注释。对于每个成员函数,并非要说明以上所有部分,因为对于每一个成员函数来说,并不是以上所有的部分都适用。但是,对于所写的每个成员函数要说明以上的部分内容。
内部注释
除成员函数注释以外,在成员函数内部还需加上注释语句来说明你的工作。 目的是使成员函数更易理解、维护和增强。
内部注释应采用两种方式:C 语言风格的注释 (/* 和 */) 和单行注释 (//)。正如上述所讨论的,应认真考虑给代码的业务逻辑采用一种风格的注释,给要注释掉的无用代码采用另外一种风格的注释。建议对业务逻辑采用单行注释,因为它可用于整行注释和行末注释。采用 C 语言风格的注释语句去掉无用的代码,因为这样仅用一个语句就可以容易地去掉几行代码。此外,因为 C 语言风格的注释语句很象文档注释符。它们之间的用法易混淆,这样会使代码的可理解性降低。所以,应尽量减少使用它们。 在函数内,一定要说明: