【发布时间】:2014-05-17 06:26:01
【问题描述】:
我正在编写一个类,它将对存储在 MyObjects 列表中的参数进行耗时的计算。由于我想轻松访问 List 的许多功能,因此我决定编写它以扩展列表类型(另一种方法是将 List 作为我的类中的字段之一并重写我将要使用的所有方法,但它看起来过于复杂)。由于计算非常复杂且耗时,而结果仅取决于存储的参数(没有时间影响,没有隐藏的依赖关系等),我决定缓存结果。所以我的代码或多或少是这样的:
public class Calculator extends ArrayList<MyObject> {
private double Result = Double.NaN;
public double getResult() {
if (Double.isNaN(Result)) {
Result = CalculateResult();
}
return Result;
}
}
这样,当第一次调用方法 getResult() 时,它会计算结果并存储它,然后在后续调用中重用。
现在,列表的内容可以用各种方法修改,很多修改都应该清除缓存。为了实现这一点,通常我会写这样的东西:
public void add(MyObject newvalue) {
super.add(newvalue);
Result = Double.NaN;
}
但是,它不起作用,因为“super”指的是泛型 ArrayList 类,所以编译器会产生类型错误。
在我的水平上一个明显的技巧是创建一个临时类,它将实现 MyObject 的 ArrayList 并使 Calculator 扩展这个临时类:
public class MyArrayList extends ArrayList<MyObject> {
}
public class Calculator extends MyArrayList {
}
但这看起来又过于复杂了。难道没有更优雅的方法来实现这个结果吗?或者,是否有类似于 SQL 中的触发器的机制,它会在对 List 进行任何修改时强制我的类清除缓存?
【问题讨论】:
-
不要扩展列表实现。这将污染您的 API 并永远将类连接到该特定实现。将其用作字段并在您的类上实现
List接口,然后将您需要的方法委托给用作字段的列表实现的实例。它有点冗长,但对您班级的用户来说更加灵活和清晰。 -
非常感谢大家的及时回复。您的示例确实解决了编译问题。然而事实上,我似乎也需要重新思考代码设计背后的基本原理。