我想确保在我的代码变得太大/太复杂而无法发布之前这将起作用。我没有足够的能力来测试这是否按我期望的方式工作
我正在做一些我想在 AST 上使用访问者模式的东西。accept(Visitor)
我的目标是通过在超类中使用反射消除在每个子类中覆盖的需要,使访问者在实现新类型的 TreeNode 时几乎透明。
通过允许visit(TreeNode)
它允许未知节点类型的默认方法,这样在添加新节点类型时不需要更改旧访问者。
类参数 R 和 P 是访问的返回值和参数,这是我在这个编程堆栈交换问题中学到的技巧。
为此,我有以下内容:
public abstract class TreeNode {
public final < R, P > R accept(TreeVisitor<R,P> v, P p){
try{
Method m = v.getClass().getMethod("visit", getClass(),Object.class);
return (R)m.invoke(v, this,p);
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
} catch (NoSuchMethodException nsme){
}
return (R)v.visit(this,p);
}
public abstract void contains(TreeNode n);//and other methods
}
//in another file
interface TreeVisitor<R,P> {
public R visit(TreeNode n,P p);//default
public R visit(TreeNodeSubclass tns,P p);
//all other subclasses as well
}
//from here lower is un-tested, written just now, just for this post, code
//somewhere else we have an algorithm to visit nodes
class DoStuff implements TreeVisitor<String,Void>{
public String visit(TreeNode n, Void v){
return n.toString();
}
public String visit(TreeNodeSubclass n, Void v){
return "SUB:" + n.toString();
}
}
//algorithm in a method somewhere
DoStuff ds = new DoStuff();
for(TreeNode node : inOrderTraverse(ROOT_NODE)){
node.accept(ds);
}
这会按我的预期工作吗(假设inOrderTraverse(ROOT_NODE)
正确生成所有节点的列表)?
我的主要问题实际上是getMethod
调用的部分,因为类型擦除Object.class
应该是正确的参数,即使p.getClass()
由于泛型参数而更喜欢使用P
。然而,这不起作用,因为类型擦除导致访问者中的实际方法签名为Object visit(this.getClass(), Object)
,this.getClass()
指的是我使用节点子类的实际类来获取访问者中正确的重载方法。
我对此的理解是正确的还是我遗漏了什么?