为分层实体设计接口

时间:2016-05-06 18:07:08

标签: java interface java-8 hierarchical default-method

我必须为分层实体设计一个接口:

interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
    T getParent();
    Stream<T> getAncestors();
}

getAncestors()方式实施默认 getParent()方法非常容易,前者将返回Stream所有方法祖先。

实施例:

default Stream<T> getAncestors() {
    Stream.Builder<T> parentsBuilder = Stream.builder();
    T parent = getParent();
    while (parent != null) {
        parentsBuilder.add(parent);
        parent = parent.getParent();
    }
    return parentsBuilder.build();
}

但我需要在流中加入this,这里出现问题。 以下行不正确,因为this的类型为HierarchicalEntity,而非T

parentsBuilder.add(this); // type mismatch!

如何重新设计界面,以便getAncestors()在结果中包含this

3 个答案:

答案 0 :(得分:2)

正如@SotiriosDelimanolis所说,没有办法完全执行此操作。但是,如果您愿意假设界面按设计使用,您可以假设thisT的实例并简单地投射它:

parentsBuilder.add((T)this);

如果要避免强制转换,可以在子类中添加要覆盖的方法:

interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
    T getParent();
    T getThis();
    default Stream<T> getAncestors() {
        // ...
        parentsBuilder.add(getThis());
        // ...
    }
}

class Foo extends HierarchicalEntity<Foo> {
    // ...
    @Override
    public Foo getThis() {
        return this;
    }
}

现在我们可以以类型安全的方式获取this,但不能保证getThis()已正确实施。它可以返回Foo的任何实例。所以,我猜你的毒药。

答案 1 :(得分:2)

创建自引用类型时,这是一个反复出现的问题。在基本类型(或界面)中,您无法强制this与[{1}}分配兼容。

当然,如果您确信所有子类型都能满足该约束条件,则可以执行Tthis的未经检查的转换。但是,只要您需要T引用this,就必须执行此未经检查的转换。

更好的解决方案是添加一个像

这样的抽象方法
T

然后,只要您需要/** All subtypes should implement this as: public T myself() { return this; } */ public abstract T myself(); 进行自我引用,就可以使用myself()代替this

T

当然,您不能强制执行该子类正确实现default Stream<T> getAncestors() { Stream.Builder<T> parentsBuilder = Stream.builder(); for(T node = myself(); node != null; node = node.getParent()) { parentsBuilder.add(parent); } return parentsBuilder.build(); } myself(),但至少,您可以轻松验证它们是否在运行时执行:

return this;

这个参考比较是一个非常便宜的操作,如果assert this == myself(); 被正确实现,总是返回myself(),HotSpot可以事先证明这个比较总是this并且忽略完全检查。

缺点是每个专业化必须具有true的冗余实现,但另一方面,它完全没有未经检查的类型转换。另一种方法是在基类中将myself() { return this; }声明为abstract作为myself(),以将未经检查的操作限制为类型层次结构的单个位置。但是,您无法验证@SuppressWarnings("unchecked") T myself() { return (T)this; }是否真的属于this ...

答案 2 :(得分:1)

添加this失败,因为HierarchicalEntity<T>不一定是T;它可能是一个未知的亚型。但是,T始终是HierarchicalEntity<T>,因为您已经这样声明了。

getAncestorsStream.Builder的返回类型从T更改为HierarchicalEntity<T>,这样您就可以添加this

default Stream<HierarchicalEntity<T>> getAncestors() {
    Stream.Builder<HierarchicalEntity<T>> parentsBuilder = Stream.builder();
    T parent = getParent();
    while (parent != null) {
        parentsBuilder.add(parent);
        parent = parent.getParent();
    }
    parentsBuilder.add(this);
    return parentsBuilder.build();
}

您也可以声明getParent也返回HierarchicalEntity<T>以保持一致。