泛型和访问者模式(Generics and the visitor pattern)

2019-09-21 14:41发布

我有Visitor模式和仿制药的问题。 我有一些抽象类,其子女都到会参观。 看看下面的代码:

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

我明白? extends Element ? extends Element不是Element 。 我的问题是:我可以表达我的想法不同的方式? 还是我刚才错过了在这种情况下,仿制药的想法?

Answer 1:

需要注意的是T<T extends SomeSuperClass>可以是一种类型的完全无关的Element和编译器必须确保对于一般的情况下visit(T t)会为每一个可能的工作T

你的代码调用Visitor.visit(Element e)但有问题的游客可以Visitor<SubElement> 。 这是没有意义的。

我认为该规定“ Element必须接受它的子类的所有访问者”无厘头:游客必须至少能够访问Element 及其所有子类 。 这将是一个Visitor<Element>

该构建体accept(Visitor<? extends Element> v)表示v可以是任何这样的Visitor<T>T extends Element 。 这并不意味着游客本身将是类型的Visitor<? extends Element> Visitor<? extends Element> 。 事实上,没有这样的事情,甚至存在于Java的。 每一位游客都会有与之相关联的特定类型的参数,而不是一个通配符。



Answer 2:

这不能工作-的游客? extends Element ? extends Element可能需要能够访问数据(属性/方法,...),其Element没有或不知道的。

你不能说是应该访问对象访问者扩展Element到一定能够访问的东西,这是一个直线Element ,甚至另一个完全独立的子Element



Answer 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 hyerarchy需要自定义visit()的实现。



Answer 4:

写这将是最一般的方法:

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

这样一来,即使是Visitor<Object>将工作(为什么不要呢)。

记住佩奇(生产者extends ,消费super )。 访问者是一个消费者,所以它应该是super



文章来源: Generics and the visitor pattern