interface BinTreeVisitor { public int forLeaf(Leaf host); public int forNode(Node host); } abstract class BinTree { static BinTreeVisitor sum = new BinTreeVisitor() { /* ANONYMOUS CLASS */ public int forLeaf(Leaf host) { return host.value; } public int forNode(Node host) { return host.left.apply(this) + host.right.apply(this); } }; static BinTreeVisitor max = new BinTreeVisitor() { /* ANONYMOUS CLASS */ public int forLeaf(Leaf host) { return host.value; } public int forNode(Node host) { int leftmax = host.left.apply(this); int rightmax = host.right.apply(this); return (leftmax > rightmax) ? leftmax : rightmax; }}; abstract int apply(BinTreeVisitor v); public static void main(String[] args) { System.out.println("Input: " + Node.n3 + " sum = " + Node.n3.apply(sum) + " max = " + Node.n3.apply(max)); System.out.println("Input: " + Node.n2 + " sum = " + Node.n2.apply(sum) + " max = " + Node.n2.apply(max)); } } class Leaf extends BinTree { static Leaf l7 = new Leaf(7); static Leaf l4 = new Leaf(4); static Leaf l3 = new Leaf(3); static Leaf l20 = new Leaf(20); int value; Leaf(int v) { value = v; }; int apply(BinTreeVisitor v) { return v.forLeaf(this); } public String toString() { return Integer.toString(value); } } class Node extends BinTree { static Node n1 = new Node(Leaf.l7, Leaf.l3); static Node n2 = new Node(Leaf.l4, n1); static Node n3 = new Node(n2, new Node(Leaf.l20, n1)); BinTree left; BinTree right; Node(BinTree l, BinTree r) { left = l; right = r; } int apply(BinTreeVisitor v) { return v.forNode(this); } public String toString() { return "(" + left.toString() + " " + right.toString() + ")"; } }