Java核心技术卷I基础知识(原书第9版)
上QQ阅读APP看书,第一时间看更新

4.3.6 封装的优点

最后,再仔细地看一下非常简单的getName方法、getSalary方法和getHireDay方法。

这些都是典型的访问器方法。由于它们只返回实例域值,因此又称为域访问器。

将name、salary和hireDay域标记为public,以此来取代独立的访问器方法会不会更容易些呢?

关键在于name是一个只读域。一旦在构造器中设置完毕,就没有任何一个办法可以对它进行修改,这样来确保name域不会受到外界的破坏。

虽然salary不是只读域,但是它只能用raiseSalary方法修改。特别是一旦这个域值出现了错误,只要调试这个方法就可以了。如果salary域是public的,破坏这个域值的捣乱者有可能会出没在任何地方。

在有些时候,需要获得或设置实例域的值。因此,应该提供下面三项内容:

●一个私有的数据域;

●一个公有的域访问器方法;

●一个公有的域更改器方法。

这样做要比提供一个简单的公有数据域复杂些,但是却有着下列明显的好处:

首先,可以改变内部实现,除了该类的方法之外,不会影响其他代码。

例如,如果将存储名字的域改为:

那么getName方法可以改为返回

对于这点改变,程序的其他部分完全不可见。

当然,为了进行新旧数据表示之间的转换,访问器方法和更改器方法有可能需要做许多工作。但是,这将为我们带来了第二点好处:更改器方法可以执行错误检查,然而直接对域进行赋值将不会进行这些处理。例如,setSalary方法可以检查薪金是否小于0。

警告:注意不要编写返回引用可变对象的访问器方法。在Employee类中就违反了这个设计原则,其中的getHireDay方法返回了一个Date类对象:

这样会破坏封装性!请看下面这段代码:

出错的原因很微妙。d和harry.hireDay引用同一个对象(请参见图4-5)。对d调用更改器方法就可以自动地改变这个雇员对象的私有状态!

图4-5 返回可变数据域的引用

如果需要返回一个可变对象的引用,应该首先对它进行克隆(clone)。对象clone是指存放在另一个位置上的对象副本。有关对象clone的详细内容将在第6章中讨论。下面是修改后的代码:

凭经验可知,如果需要返回一个可变数据域的拷贝,就应该使用clone。