/** 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);
}
}