泛型和访客模式

时间:2012-08-24 12:47:35

标签: java generics visitor-pattern

我遇到了访问者模式和泛型问题。我有一些抽象的班级,他们的孩子将被访问。看看这段代码:

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);
}

所以我的想法是:我有一些类层次结构(例如ElementSomeSuperClass的子类)。 我有一些通用的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。我的问题是:我可以用不同的方式表达我的想法吗?或者我在这种情况下错过了泛型的想法?

4 个答案:

答案 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