/** With this improved interface, the connection between the visitor * pattern and pattern matching is much move obvious. */ public final class VisitorImproved { public interface Shape { public A match(ShapeCases cases); } public interface ShapeCases { public A caseCircle(Double x, Double y, Double r); public A caseRectangle(Double x, Double y, Double w, Double h); } public static final Shape newCircle(Double x, Double y, Double r) { return new Shape() { public A match(ShapeCases cases) { return cases.caseCircle(x, y, r); } }; } public static final Shape newRectangle(Double x, Double y, Double w, Double h) { return new Shape() { public A match(ShapeCases cases) { return cases.caseRectangle(x, y, w, h); } }; } public static final Shape exampleCircle = newCircle(2.0, 1.4, 4.5); public static final Shape exampleRectangle = newRectangle(1.3, 3.1, 10.3, 7.7); public static final Double area(Shape shape) { return shape.match(new ShapeCases() { public Double caseCircle(Double x, Double y, Double r) { return 2 * Math.PI * Math.pow(r, 2); } public Double caseRectangle(Double x, Double y, Double w, Double h) { return w * h; } }); } public static final Shape translate(Shape shape, Double dx, Double dy) { return shape.match(new ShapeCases() { public Shape caseCircle(Double x, Double y, Double r) { return newCircle(x + dx, y + dy, r); } public Shape caseRectangle(Double x, Double y, Double w, Double h) { return newRectangle(x + dx, y + dy, w, h); } }); } public static final String show(Shape shape) { return shape.match(new ShapeCases() { public String caseCircle(Double x, Double y, Double r) { return String.format("Circle {x = %f, y = %f, r = %f}", x, y, r); } public String caseRectangle(Double x, Double y, Double w, Double h) { return String.format("Rectangle {x = %f, y = %f, w = %f, h = %f}", x, y, w, h); } }); } public static final void main(String[] args) { String circleString = show(translate(exampleCircle, 3.0, 4.0)); String rectangleString = show(translate(exampleRectangle, -4.0, -3.0)); System.out.println(circleString); System.out.println(rectangleString); } }