有时候,可能会编写一些退化类(degenerate classes),没什么用,只是用来集中实例域:
// Degenerate classes like this should not be public!
class Point {
public double x;
public double y;
}
由于这种类的数据域是可以被直接访问的,这些类没有提供封装(encapsulation)(第 15 项)。如果不改变 API,就无法改变他的数据表示法,也无法强加任何约束条件;当字段被访问的时候,无法采取任何辅助的行为。坚持面向对象程序设计的程序猿面对这种类深恶痛绝,认为应该用包含私有字段和公共访问方法(getters)的类代替。对于可变的类来说,应该用包含私有字段和公有设置方法(setters)的类代替:
// Encapsulation of data by accessor methods and mutators
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double x) { this.x = x; }
public void setY(double y) { this.y = y; }
}
毫无疑问,说到公有类的时候,坚持面向对象程序设计思想的看法是正确的:如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改变该类的内部表示法的灵活性。如果公有类暴露了它的数据字段,要想在将来改变其内部表示法是不可能的,因为公有类的客户端代码已经遍布各处了。
然而,一个类是包级私有的,或者是私有的嵌套类,直接暴露它的数据字段并没有本质的错误 ———— 假设这些数据字段确实描述了该类所提供的抽象。这种方法比访问方法的做法更不会产生视觉混乱,虽然客户端代码与该类的内部表示法紧密相连,但是这些代码被限定在包含该类的包中。如果有必要更改表示法,你可以在不触及包外的任何代码的情况下进行更改。对于私有嵌套类,更改的范围进一步限制为封闭类【内部类所在的外围类】中。
Java 平台库中的几个类违反了公共类不应直接公开字段的建议。显著的例子包括 java.awt 包中的 Point 和 Dimension 类。它们是不值得效仿的例子,相反,这些类应该被当做反面的警告示例。正如第 67 项所述,暴露 Dimension 类内部数据造成了严重的性能问题,这个问题至今仍然存在。
虽然让公有类直接暴露字段永远不是一个好主意,但如果字段是不可变的,这种做法的危害就比较小一点。如果不改变类的 API,就无法改变这种类的表示法,当字段被读取的时候,你也无法采取辅助操作,但是可以强加约束条件。例如,这个类确保了每个实例都表示一个有效的时间:
// Public class with exposed immutable fields - questionable
public final class Time {
private static final int HOURS_PER_DAY = 24;
private static final int MINUTES_PER_HOUR = 60;
public final int hour;
public final int minute;
public Time(int hour, int minute) {
if (hour < 0 || hour >= HOURS_PER_DAY)
throw new IllegalArgumentException("Hour: " + hour);
if (minute < 0 || minute >= MINUTES_PER_HOUR)
throw new IllegalArgumentException("Min: " + minute);
this.hour = hour;
this.minute = minute;
}
... // Remainder omitted
}
总之,公有类永远都不应该暴露可变字段,但是让公有类暴露不可变的字段其危害比较小。但是,有时候会需要用包级私有的或者私有的嵌套类来暴露字段,无论这个类是可变的还是不可变的。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。