コードが大きくなりすぎたり複雑になりすぎて投稿できなくなる前に、これが機能することを確認したいと思います。これが期待どおりに機能するかどうかをテストするのに十分なものがありません
私は、AST で Visitor パターンを使用したいものに取り組んでいます。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
が正しいパラメータである必要があるためです。ただし、型消去により Visitor の実際のメソッド シグネチャが になるため、それは機能しません。これは、Node のサブクラスの実際のクラスを使用して、Visitor で適切なオーバーロードされたメソッドを取得しているという事実を参照しています。p.getClass()
P
Object visit(this.getClass(), Object)
this.getClass()
これについての私の理解は正しいですか、それとも何か不足していますか?