我有一个关于结构创建的难题:一个表示一般物理变换的接口变换,以及一个表示特定变换类型的类PoincareTransform。我想做这样的事情
public interface Transform {
public Transform compose(Transform t);
}
public class PoincareTransform implements Transform {
private Matrix matrix;
public Transform compose(Transform t) {
...
}
}
但是我希望那个方法组合(变换T)只采用PoicareTransform,因为必须有一个矩阵来组合。一种可能的解决方案是使用泛型
public interface Transform<T extends Transform<T>> {
public T compose(T t);
}
public class PoincareTransform implements Transform<PoincareTransform> {
private Matrix matrix;
public PoincareTransform compose(PoincareTransform t) {
...
}
}
但这并不令人满意,因为它在概念上并不干净,优雅并且再次出现问题:PoincareTransform子类现在具有与以前相同的问题。另外,根据这个定义,我的项目周围都有泛型!
我在概念上是错的?我怎么能建立一个我想到的这样的结构?
答案 0 :(得分:0)
我想我会选择你的第一个解决方案,但如果你无法从PoincareTransform.transform(Transform t)
中的给定转换中获得矩阵,则会返回错误。
例如:
public class PoincareTransform implements Transform {
private Matrix matrix;
public Transform compose(Transform t) {
if (!t.hasMatrix()) {
// Throw an exception, or some other meaningful error.
}
...
}
}
这样,它是通用的,所以如果你最终使用矩阵进行不同类型的变换,那么你可以使用它。
另一方面,如果您真的只想操作PoincareTransforms,可以使用instanceof
运算符检查传入的实例是否正确。
public class PoincareTransform implements Transform {
private Matrix matrix;
public Transform compose(Transform t) {
if (!t instanceof PoincarTransform) {
// Throw an exception, or some other meaningful error.
}
PoincarTransform p = (PoincarTransform)t;
...
}
}
答案 1 :(得分:0)
你在谈论协变参数类型,我不相信你可以在java的类型系统中编码。它会违反Liskov的原则:如果超类型声明它可以接受某种类型T的值,那么子类型必须至少接受它。 (但允许的是逆变量参数类型:子类型可以接受更多类型而不是其超类型(在您的情况下,Liskov将允许PoincoreTransform.compose接受对象而不是变换),但这又是AFAIK在java中不受支持。)
恕我直言,最干净的解决方案是放弃编译时间检查并解决运行时检查的想法:在子类型中使用instanceof以确保参数具有正确的Transform子类型(如我前面的海报所示)