【发布时间】:2020-09-21 00:36:03
【问题描述】:
挑战
给定一个具有重要 getter 的类和一些其他内部方法访问相同的 private 成员字段:
有效示例
class TestType {
private String value;
public String getValue() {
return this.value == null || this.value.isEmpty() ? "default" : this.value;
}
public void setValue(String newValue) {
this.value = newValue;
}
public int getValueLength() {
return this.getValue().length();
}
}
我想禁止在getValueLength() 方法中绕过getter。
getValueLength() 的以下实现应该会产生某种错误(单元测试失败、checkstyle 错误或其他任何可以以通用方式自动化的错误):
方法无效
public int getValueLength() {
// ERROR: possible NullPointerException
return this.value.length();
}
背景
在我的实际代码中,getter 内部进行了一些延迟加载,仅在第一次访问时才加载实际值。先调用getValueLength() 可能会直接导致NullPointerException 或者基于缺失值执行错误操作。
这样做的动机是确保未来的开发人员不会忘记只使用 getter 方法而永远不会直接访问成员。由于这是一个孤立的问题(即仅在专门添加这种延迟加载的情况下),如果需要一些额外的注释是可以接受的,例如在成员本身上,它应该只在选定的方法中访问,并且这些方法也被标记 - 或特定的 checkstyle cmets 启用/禁用特定规则。
【问题讨论】:
-
为什么不将
value初始化为"default"而不是null?不再有 NPE,也不再有惰性初始化 -
必须在同一个班级吗?您可以将
value包装在LazyValue类中 -
value可能总是有一个不直观的名称,例如$value$,这会让未来的开发人员在访问它之前再看一遍 -
封装的重点是对类的使用者隐藏实现细节。当您 从实现本身 隐藏这些细节时,这没有多大意义,所以我认为 OP 的问题更多是“我如何确保我不会意外使用这个字段而不是我的 getter在做这堂课的时候”。为此,删除惰性初始化或包装在一个对象中(以描述它的作用)将是最好的imo。不喜欢晦涩的变量名。
-
(1) 根据“背景”部分,预先初始化值会破坏延迟加载大量几乎不使用的数据的目的,在这个特定示例中,可以设置值稍后转至
null(2) 包装成LazyValue可能是一种选择,但由于返回类型不同,会阻止我们的工具检测到getter 和setter,(3) 奇怪的名称会与其他现有的规则,不是那么好。开发者不知道这个名字为什么这么奇怪。
标签: java getter-setter checkstyle