【发布时间】:2015-06-26 17:33:55
【问题描述】:
这是一个用 Java 实现的访问者模式,用于计算 (1 + 2) + 3 之类的表达式。此处的代码受到以下代码示例的启发:https://en.wikipedia.org/wiki/Visitor_pattern#Sources。
interface Node
{
public int accept(Visitor v);
}
class ConstantNode implements Node
{
public int constant;
public ConstantNode(int constant)
{
this.constant = constant;
}
public int accept(Visitor v) {
return v.visit(this);
}
}
class SumNode implements Node
{
public Node left;
public Node right;
public SumNode(Node left, Node right)
{
this.left = left;
this.right = right;
}
public int accept(Visitor v) {
return v.visit(this);
}
}
interface Visitor
{
public int visit(ConstantNode n);
public int visit(SumNode n);
}
class EvalVisitor implements Visitor
{
public int visit(ConstantNode n) {
return n.constant;
}
public int visit(SumNode n) {
return n.left.accept(this) + n.right.accept(this);
}
}
public class VisitorDemo
{
public static void main(String[] args)
{
// First make an expression tree to represent the following.
//
// +
// / \
// + 3
// / \
// 1 2
Node a = new ConstantNode(1);
Node b = new ConstantNode(2);
Node c = new ConstantNode(3);
Node d = new SumNode(a, b);
Node e = new SumNode(d, c);
Visitor visitor = new EvalVisitor();
int result = e.accept(visitor);
System.out.println(result);
}
}
我了解在每个递归级别,调用哪个visit() 方法取决于访问者的类型(在本例中为evalVisitor)以及节点的类型(ConstantNode 或@987654326 @),因此需要双重调度。但是这种使用accept() 和visit() 方法实现双重调度的编码对我来说似乎太复杂了。但我所见过的几乎所有访问者模式示例都使用这种方法,即通过accept() 将访问者传递给节点,这反过来又调用访问者的visit() 方法来执行双重调度。
为什么代码示例不能像这样更简单?
interface Node
{
}
class ConstantNode implements Node
{
public int constant;
public ConstantNode(int constant)
{
this.constant = constant;
}
}
class SumNode implements Node
{
public Node left;
public Node right;
public SumNode(Node left, Node right)
{
this.left = left;
this.right = right;
}
}
interface Visitor
{
public int visit(Node n) throws Exception;
}
class EvalVisitor implements Visitor
{
public int visit(Node n) throws Exception {
if (n instanceof ConstantNode) {
return ((ConstantNode) n).constant;
} else if (n instanceof SumNode) {
return this.visit(((SumNode) n).left) + this.visit(((SumNode) n).right);
} else {
throw new Exception("Unsupported node");
}
}
}
public class SimpleVisitorDemo
{
public static void main(String[] args) throws Exception
{
// First make an expression tree to represent the following.
//
// +
// / \
// + 3
// / \
// 1 2
Node a = new ConstantNode(1);
Node b = new ConstantNode(2);
Node c = new ConstantNode(3);
Node d = new SumNode(a, b);
Node e = new SumNode(d, c);
Visitor visitor = new EvalVisitor();
int result = visitor.visit(e);
System.out.println(result);
}
}
在这个代码示例中,我完全消除了在每个节点中实现apply() 的需要,并且包括双分派逻辑在内的整个访问逻辑现在只包含在访问者类中。
我有以下问题:
您能否客观地列举简化访问者模式在代码的可维护性或效率方面存在的问题?
【问题讨论】:
标签: java visitor-pattern