3

我遇到了访问者模式和泛型的问题。我有一些抽象类要访问其孩子。看看这段代码:

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 ElementVisitor<capture#1-of ? extends Element>不适用于参数(Element)。

我明白? extends Element不是Element。我的问题是:我可以用不同的方式表达我的想法吗?或者我只是在这种情况下错过了泛型的想法?

4

4 回答 4

3

那是行不通的——访问者? extends Element可能需要能够访问Element不知道或不知道的数据(属性/方法,...)。

您无法获得应该访问扩展Element为必然能够访问直接Element或什至另一个完全独立的子类的对象的访问者Element

于 2012-08-24T12:51:52.097 回答
3

我认为您尝试做的事情没有多大意义。使Visitor泛型化是没有用的:该accept()方法必须将特定的访问者接口作为参数,以便 的子类Element可以调用特定的重载visit().

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()实现的所有类。

于 2012-08-24T13:28:39.253 回答
2

请注意,Tin<T extends SomeSuperClass>可以是完全不相关的类型Element,编译器必须确保适用visit(T t)于所有可能的一般情况T

您调用的代码Visitor.visit(Element e),但有问题的访问者可能是Visitor<SubElement>。那是没有意义的。

我认为“Element必须接受其子类的所有访问者”的要求没有意义:访问者必须至少能够访问Element 及其所有子类。那将是一个Visitor<Element>.

构造accept(Visitor<? extends Element> v)意味着 thatv可以是任何这样Visitor<T>T extends Element。这并不意味着访问者本身将属于 类型Visitor<? extends Element>。事实上,Java 中甚至不存在这样的东西。每个访问者都有一个与之关联的特定类型参数,而不是通配符。

于 2012-08-24T12:55:32.047 回答
2

最一般的写法是:

public void accept(Visitor<? super Element> v) {
    v.visit(this);
}

这样,即使 aVisitor<Object>也可以工作(为什么不应该)。

记住 PECS(生产者extends,消费者super)。访客是消费者,所以它应该是super

于 2012-08-24T19:57:48.860 回答