可见性 public 说明 一个公共字段可被任何其他对象或者类中的成员函数访问。 被保护的字段可被它声明时所在的类及该类的子类的所有成员函数访问。 正确用法 不要让字段公有。 protected 不要让字段被保护。 private 私有字段只可以被它声明时所在的类的其它成员函数调用,该类子类中的函数不可以调用。 所有的字段都应置为私有,由获取和设置成员函数(存取函数)访问。 对于那些非长期性的字段(它们不被永久保留),应将它们标注为 static 或 transient [DES97]。 使它们与 BDK 的约定一致。
不要“隐藏”名字
名字隐藏是指给局部变量、参数或者字段所取的名字,与另一个更大范围内定义的变量、参数或者字段的名字相同(或相似)。例如,如果把一个字段叫做 firstName ,就不要再生成一个局部变量或者参数叫做 firstName,或者任何类似的名字,如 firstNames 或 fistName。名字隐藏会使代码难于理解,并容易产生问题。因为你或者其他开发者在修改代码时,会误读代码,而错误又很难发现。
注释一个字段
所有的字段都应很好地加以注释,以便其他开发者理解它。要想有效地注释,以下的部分需要说明:
1.字段的说明。需说明一个字段,才能使人了解如何使用它。
2.注释出所有采用的不变量。字段中的不变量是指永远为“真”的条件。
例如,字段 dayOfMonth 的不变量可能是它的值只能在 1 到 31 之间(显然,可以用基于某一年里的某个月份来限制这个字段值,使其变的更加复杂)。通过说明字段值的限制条件,有助于定义重要的业务规则,使代码更易理解。
3.示例。对于那些有复杂业务规则与之相关联的字段,应提供几个例子,使它们容易理解。一个例子常象一幅画:它抵得上几千个词语。 4.并行事件。对众多程序开发者来说,并行性是一个新而复杂的概念;
事实上,即使对有经验的并行程序开发者来说,并行性也是一个老但却复杂的课题。最终结果是,如果应用了 Java 的并行编程特性,那么你应在程序中详细地注释出来。 5. 可见性决策。如果声明了一个非私有字段,则应说明为什么要这样做。
字段的可见性在上文中(第 3.2 节“字段的可见性”)讨论了,支持封装的存取成员函数的用法将在下文(第 3.4 节“存取成员函数的使用”)中讨论。总的来说,最好能有一个好的理由解释为什么不将变量声明为私有类型。
使用存取成员函数
除了满足命名约定之外,适当地使用存取成员函数,即提供更新或访问字段值的成员函数,可以实现字段的可维护性。存取成员函数有两种:设置函数(也叫变化函数)和获取函数。设置函数修改变量的值,获取函数取到变量的值。
虽然存取成员函数往往会增加代码费用,但是现在 Java 编译器使用时已被优化,所以存取成员函数会增加代码费用这一点已不再正确。存取函数帮助隐藏了类的具体实现细节。一个变量仅能访问两个控制点:设置函数和获取函数。让需修改的点最小化,增加了类的可维护性。Java 代码的优化将在(第 7.3 节“优化 Java 代码”)中讨论。
你的机构能改进的最重要的标准之一是存取函数的使用。一些开发者不愿使用存取成员函数的原因是,他们不想多输入几个键(例如,对于一个获取函数,除了字段名之外,还必须输入 in, get 和())。最主要的是,采用存取函数后增加的可维护性和可扩展性,远远超过输入这些字符所做的工作。
存取函数是唯一可以访问字段的地方。正确使用存取成员函数的关键概
念是:成员函数中,只有存取成员函数可以直接访问字段。的确,定义字段的类内的其它成员函数可能可以直接访问该私有字段,但是这样做会增加类内的耦合,所以不应这样。
为什么采用存取函数?
“好的程序设计试图将程序部件与不必要、未计划或者不需的外部影响分隔开来。访问修饰语句(存取函数)给编程语言控制这一类的接触提供了一种清晰并可检验的方法。”[KAN97] 存取成员函数通过以下方法提高类的可维护性:
1.更新字段。.每个字段只有几个单点要更新,这使得修改和检测都很容
易。换句话说,字段已被封装。
2.获得字段的值。你完全控制着字段应怎样被访问以及被谁访问。 3.获取常量名和类名。在获取函数中封装常量值和类名,当这些值或名
字改变时,只需更新获取函数内的值,而并非常量或者名字被使用
处的每一行代码。
4.初始化字段。采用滞后初始化 (lazy initialization) 保证字段总能被初
始化,并且只在需要时才初始化。 5.减少类与子类之间的耦合。 当子类通过它们相应的存取成员函数访问
被继承的字段时,它可以不影响它的任何子类,而只修改超类字段
的实现方式,这样有效地减少了超类与子类之间的耦合。存取函数减少了那种一旦超类被修改就会波及子类的“脆弱基类”的风险。 6.将变化封装到字段中。如果一个或者多个字段的业务规则变化了,可
以只潜在地修改存取函数,就同样可以提供规则变化之前的功能。
这一点使你很容易响应新的业务规则。
7.简化并行事件。[LEA97] 指出,如果采用了基于字段值的 waits 语句,
那么设置成员函数提供了一个位置可包含 notifyAll。这让转向并行解决方案更加容易。 8. 名字隐藏不再是一个大问题。虽然应该避免名字隐藏,即避免赋给局
部变量一个与字段相同的名字,但是始终通过存取函数访问字段意
味着可以给局部变量任何你想取的名字。不必担心字段名的隐藏,因为你无论如何都不会直接访问它们。
当不用存取函数时:唯一可能你不想用存取函数的时候是当执行时间最重要时。但是,这实际上很少见,因为应用程序耦合性的增加会平衡掉这样做之后赢得的好处。
命名存取函数
获取成员函数应在名字中加上 get + 字段名,除非字段表示的是一个布尔值(“真”或者“假”),这时获取函数名中应加上 is + 字段名。无论何种字段类型,设置成员函数应在名字中加上 set + 字段名 [GOS96],[DES97]。注意字段名始终采用大小写混合,所有单词的第一个字母要大写。命名约定在 JDK 中被始终使用,在 beans development 中也必须使用。 Examples:
字段 firstName 类型 字符串 地址 对象 获取函数名 getFirstName() getAddress() 设置函数名 setFirstName() setAddress() address persistent 布尔值 customerNo 整型 isPersistent() setPersistent() getCustomerNo() setCustomerNo() orderItems OrderItem 的对象数组 getOrderItems() setOrderItems() 存取函数的高级技术
存取函数不仅仅局限在获取和设置实例的字段值时使用。这一节讨论如何将存取函数应用于以下方面,以提高代码的适应性:
? 初始化字段值 ? 访问常量值 ? 访问集合
? 同时访问几个字段
滞后初始化
在访问变量前需要将其初始化。 对于初始化有两种想法:当对象生成时初始化所有的变量(传统方法)或者在第一次使用变量时进行初始化。第一种方式在对象初次创建时调用特殊的成员函数,这些成员函数叫做构造函数。虽然这种方法可行,但是它被证明常常产生错误。当增加一个新的变量时,你很容易就会忘记更新构造函数(另一种称为滞后初始化的方法是,字段由它们的获取函数初始化。如下文所示(注意在获取函数内是如何采用一个设置函数的)。注意:成员函数检查支行个数是否为零,若是则将个数设置为适当的默认值。
/** 返回支行号,支行号 是整个帐号的最左边四位数字。 帐号的格式是 BBBBAAAAAA。 */
protected int getBranchNumber() {
if( branchNumber == 0) {
// 默认支行号是 1000,
// 它是 Bedrock 城市中心的一个主要支行 setBranchNumber(1000); }
return branchNumber; }
对于在数据库中实际存放的是其它对象的字段,常采用滞后初始化。例如,当生成一个新的存货清单项时,不必从默认的数据库中获得存货项的类型。而仅仅是在第一次访问该项时,才需用滞后初始化方式设定它的值。这样当需要时,只需从数据库中读出存货项类型对象即可。这种方法对于那些有不常被访问的字段的对象有好处。如果你不打算用这些东西,为什么花精力从固定存取中获取它们呢?
只要获取函数采用了滞后初始化方式,就应该象上文例子那样说明为什么采用那个默认值。 这样做除去了代码中字段是如何被应用的那层神秘,使代码的可维护性和可扩展性都得到了提高。 常量存取函数
Java 中的代码模式是将常量值作为静态常量字段。这种方式对于“常量”是可以理解的,因为它们是固定的。例如,布尔类使用“真”和“假”这两个静态最终字段,它们代表这个类的两个实例。DAYS_IN_A_WEEK 这个常量的值可能永不会改变,这一点也可以理解。
但是,随时间流逝,许多事物“常量”因为业务规则的变化而发生变化。例如:Archon Bank of Cardassia (ABC) 一直坚持若要获取利息,一个帐户至少应有 $500 的余额。要实现这一点,我们可以在计算利息的成员函数的类 Account 中增加一个叫做
MINIMUM_BALANCE 的静态字段。这虽然可行,但却不灵活。如果业务规则变化为不同种类的帐户有不同的最小余额限制,比如说,储蓄帐户的最小余额为 $500 ,支票帐号的最小余额为 $200,那么又该怎么办呢?又如果业务规则变化为第一年要保持 $500 的最小余额,第二年要保持 $400 的最小余额,第三年要保持 $300 的最小余额,这又应该怎么办呢?要是规则变为夏季应有 $500 ,但冬季应有 $250 呢?可能所有这些规则的组合在不久的将来就会采用。