为分层实体设计接口 [英] Designing interface for hierarchical entity
问题描述
我必须为分层实体设计一个接口:
interface HierarchicalEntity< T extends HierarchicalEntity< T>> {
T getParent();
Stream< T> getAncestors();
}
实施默认 <$ c非常容易$ c> getAncestors()以 getParent()
的方式,前者将返回 Stream
所有祖先。
实施例:
默认流< T> getAncestors(){
Stream.Builder< T> parentsBuilder = Stream.builder();
T parent = getParent();
while(parent!= null){
parentsBuilder.add(parent);
parent = parent.getParent();
}
返回parentsBuilder.build();
}
但我还需要包含这个
进入流,这里出现问题。
以下行不正确,因为此
的类型为 HierarchicalEntity
,而不是 T
:
parentsBuilder.add(this); // 类型不匹配!
如何重新设计界面以使 getAncestors()
在结果中包含此
?
这是创建自引用类型时反复出现的问题。在基本类型(或接口)中,您不能强制执行此
将与 T
兼容。 / p>
当然,您可以执行未经检查的此
转换为 T
如果您确信所有子类型都能满足该约束条件。但是当你需要这个
引用时,你必须执行这个未经检查的强制转换为 T
。
更好的解决方案是添加一个抽象方法,如
/ **
全部子类型应该实现为:
public T myself(){
return this;
}
* /
public abstract T myself();
然后,您可以使用我自己()
而不是这个
,只要你需要自我引用为 T
。
默认流< T> getAncestors(){
Stream.Builder< T> parentsBuilder = Stream.builder();
for(T node = myself(); node!= null; node = node.getParent()){
parentsBuilder.add(parent);
}
返回parentsBuilder.build();
}
当然,您无法强制执行该子类正确实现我自己()
作为返回此;
,但至少,您可以轻松验证它们是否在运行时执行:
断言这个==我自己();
这个参考比较是一个非常便宜的操作,如果我自己()
正确实现为总是返回此
,HotSpot可以提前证明此比较将始终为 true
并完全取消支票。
缺点是每个专业化必须有我自己()的冗余实现{return this; }
,但另一方面,它完全没有未经检查的类型转换。另一种方法是在基类中将 abstract
的非 abstract
声明为 @SuppressWarnings(unchecked)T我自己(){return(T)this; }
将未经检查的操作限制为类型层次结构的单个位置。但是,你无法验证这个
是否真的属于 T
...
I have to design an interface for hierarchical entity:
interface HierarchicalEntity<T extends HierarchicalEntity<T>> {
T getParent();
Stream<T> getAncestors();
}
It's quite easy to implement default getAncestors()
method in terms of getParent()
in such a way that the former would return Stream
of all the ancestors.
Implementation example:
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();
}
But I need to also include this
into the stream, and here a problem appears.
The following line is not correct because this
is of type HierarchicalEntity
, not T
:
parentsBuilder.add(this); // type mismatch!
How can I redesign the interface in order to make getAncestors()
include this
into the result?
It’s a recurring problem when creating self-referential types. In the base type (or interface), you can’t enforce that this
will be assignment compatible with T
.
Of course, you can perform an unchecked cast of this
to T
if you are confident that all subtypes will fulfill that constraint. But you have to perform this unchecked cast whenever you need a this
reference as T
.
The better solution is to add an abstract method like
/**
All subtypes should implement this as:
public T myself() {
return this;
}
*/
public abstract T myself();
Then, you can use myself()
instead of this
whenever you need a self-reference as 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();
}
Of course, you can’t enforce that subclasses correctly implement myself()
as return this;
, but at least, you can easily verify whether they do at runtime:
assert this == myself();
This reference comparison is a very cheap operation and, if myself()
is correctly implemented as invariably returning this
, HotSpot can prove in advance that this comparison will always be true
and elide the check completely.
The drawback is that each specialization will have to have this redundant implementation of myself() { return this; }
, but on the other hand, it’s completely free of unchecked type casts. The alternative is to have an non-abstract
declaration of myself()
in the base class as @SuppressWarnings("unchecked") T myself() { return (T)this; }
to limit the unchecked operation to a single place for the type hierarchy. But then, you can’t verify whether this
really is of type T
…
这篇关于为分层实体设计接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!