[英]Java Generics with Reflection for Visitor Pattern
我想確保在我的代碼變得太大/太復雜而無法發布之前,它能夠正常工作。 我沒有足夠的方法來測試這是否符合我的預期
我正在做一些我想在AST上使用Visitor模式的事情。 我的目標是通過在超類中使用反射來消除在每個子類中覆蓋accept(Visitor)
的需要,從而在實現新型TreeNode時使訪問者幾乎透明。
通過允許visit(TreeNode)
它允許使用未知節點類型的默認方法,這樣,當添加新的節點類型時,無需更改舊訪客。
類Parameters 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
人們更願意使用p.getClass()
。 但是,這將不起作用,因為類型擦除會導致Visitor中的實際方法簽名為Object visit(this.getClass(), Object)
, this.getClass()
引用我正在使用的實際類的事實Node的子類,以在Visitor中獲得正確的重載方法。
我對此是否正確理解還是缺少某些東西?
我不確定如果將Object.class作為參數類型進行傳遞是否會起作用,但是我確實看到了另一個潛在的問題:如果新節點具有私有而不是公共的“訪問”方法,則應考慮例外,例如:
try{ Method m = v.getClass().getMethod("visit", getClass(),Object.class); return (R)m.invoke(v, this,p); } catch (NoSuchMethodException e) { try { Method m = v.getClass().getDeclaredMethod("visit", getClass(),Object.class); return (R)m.invoke(v, this,p); } catch (Exception e){ return (R)v.visit(this,p);//default } } catch (Exception e){ return (R)v.visit(this,p);//default }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.