即使在Java中,结构也有其位置。仅当满足以下两个条件时,才应使用它们:
- 您只需要聚合没有任何行为的数据,例如作为参数传递
- 聚合数据具有哪种值并不重要
如果是这种情况,则应将这些字段设为公开字段,并跳过获取/设置方法。无论如何,getter和setter都是笨拙的,而Java由于没有像有用语言这样的属性而很愚蠢。由于类结构对象无论如何都不应具有任何方法,因此公共字段最有意义。
但是,如果其中任何一个都不适用,那么您正在处理一个真实的类。这意味着所有字段都应该是私有的。(如果您绝对需要在更易于访问的范围内的字段,请使用getter / setter。)
要检查您的假定结构是否有行为,请查看何时使用这些字段。如果它似乎违反告诉,不要问,那么您需要将该行为移入您的班级。
如果您的某些数据不应更改,那么您需要将所有这些字段定为最终字段。您可能会考虑使您的班级一成不变。如果需要验证数据,请在设置器和构造函数中提供验证。(一个有用的技巧是定义一个私有的setter,并仅使用该setter来修改您的类中的字段。)
您的Bottle示例很可能在两个测试中均未通过。您可能拥有(伪造的)代码,如下所示:
public double calculateVolumeAsCylinder(Bottle bottle) {
return bottle.height * (bottle.diameter / 2.0) * Math.PI);
}
相反,它应该是
double volume = bottle.calculateVolumeAsCylinder();
如果更改高度和直径,它会是同一瓶吗?可能不是。这些应该是最终的。直径是否可以为负值?瓶子的高度必须比宽度高吗?上限可以为空吗?没有?您如何验证这一点?假设客户是愚蠢或邪恶的。(无法分辨出差异。)您需要检查这些值。
这是您新的Bottle类的样子:
public class Bottle {
private final int height, diameter;
private Cap capType;
public Bottle(final int height, final int diameter, final Cap capType) {
if (diameter < 1) throw new IllegalArgumentException("diameter must be positive");
if (height < diameter) throw new IllegalArgumentException("bottle must be taller than its diameter");
setCapType(capType);
this.height = height;
this.diameter = diameter;
}
public double getVolumeAsCylinder() {
return height * (diameter / 2.0) * Math.PI;
}
public void setCapType(final Cap capType) {
if (capType == null) throw new NullPointerException("capType cannot be null");
this.capType = capType;
}
// potentially more methods...
}