我遇到了访问者模式和泛型问题。我有一些抽象的班级,他们的孩子将被访问。看看这段代码:
public abstract class Element extends SomeSuperClass {
public void accept(Visitor<? extends Element> v) {
v.visit(this);
}
}
public interface Visitor<T extends SomeSuperClass> {
void visit(T element);
}
所以我的想法是:我有一些类层次结构(例如Element
是SomeSuperClass
的子类)。
我有一些通用的Visitor
接口来访问这个层次结构。现在在这个层次结构的中间是Element
类,它是抽象的并且拥有它自己的子类。
现在我希望Element
接受其子类的所有访问者,这就是我放这行的原因:
public void accept(Visitor<? extends Element> v)
但现在我收到了错误:
capture#1-of ? extends Element
类型中的方法访问(Visitor<capture#1-of ? extends Element>
)不适用于参数(Element
)。
我了解? extends Element
不是Element
。我的问题是:我可以用不同的方式表达我的想法吗?或者我在这种情况下错过了泛型的想法?
答案 0 :(得分:3)
这不起作用 - ? extends Element
的访问者可能需要能够访问Element
没有或不知道的数据(属性/方法......)。
您无法访问应该访问扩展Element
的对象的访问者,以便能够访问Element
甚至是{{1}的另一个完全独立的子类的内容。 }。
答案 1 :(得分:3)
我认为你想要做的事情没有多大意义。使Visitor
泛型无用:accept()
方法必须将特定的访问者接口作为参数,以便Element
的子类可以调用visit()
的特定重载。 / p>
interface Visitor {
void visit(Element e);
void visit(SubElement e);
}
class Element {
public void accept(Visitor v) {
v.visit(this);
}
}
class SubElement {
public void accept(Visitor v) {
v.visit(this);
}
}
class ElementVisitor implements Visitor {
public void visit(Element e) {}
public void visit(SubElement e) {}
}
请注意,Visitor
接口必须知道需要自定义Element
实现的visit()
层次结构中的所有类。
答案 2 :(得分:2)
请注意T
中的<T extends SomeSuperClass>
可以是与Element
完全无关的类型,编译器必须确保visit(T t)
适用于所有可能T
的一般情况Visitor.visit(Element e)
1}}。
您调用的代码Visitor<SubElement>
,但相关访问者可能是Element
。这没有意义。
我认为要求“Element
必须接受其子类的所有访问者”没有意义:访问者必须至少能够访问Visitor<Element>
及其所有子类< / strong>即可。那将是accept(Visitor<? extends Element> v)
。
构造v
表示Visitor<T>
可以是T extends Element
Visitor<? extends Element>
。 不表示访问者本身属于{{1}}类型。事实上,Java中甚至不存在这样的事情。每个访问者都有一个与之关联的特定类型参数,而不是通配符。
答案 3 :(得分:2)
编写它的最常用方法是:
public void accept(Visitor<? super Element> v) {
v.visit(this);
}
这样,即使是Visitor<Object>
也行不通(为什么不应该这样)。
记住PECS(制作人extends
,消费者super
)。访问者是消费者,因此应该是super
。