diff --git a/pom.xml b/pom.xml index 1833bb1..36acf9c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,6 +9,16 @@ 1.0-SNAPSHOT + + + org.derive4j + derive4j + 0.7 + + true + + + diff --git a/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java b/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java index 4c5a4b9..7c70d94 100644 --- a/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java +++ b/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java @@ -6,35 +6,12 @@ import java.util.Map; import java.util.function.Function; -public class VisitorLambda { - - public static class LambdaVisitor implements Function { - private Map, Function> fMap = new HashMap<>(); - - public Acceptor on(Class clazz) { - return new Acceptor<>(this, clazz); - } - - @Override - public A apply( Object o ) { - return fMap.get(o.getClass()).apply( o ); - } - - static class Acceptor { - private final LambdaVisitor visitor; - private final Class clazz; +import static org.mfusco.fromgoftolambda.examples.visitor.Elements.circleElement; +import static org.mfusco.fromgoftolambda.examples.visitor.Elements.rectangleElement; +import static org.mfusco.fromgoftolambda.examples.visitor.Elements.squareElement; - public Acceptor( LambdaVisitor visitor, Class clazz ) { - this.visitor = visitor; - this.clazz = clazz; - } +public class VisitorLambda { - public LambdaVisitor then(Function f) { - visitor.fMap.put( clazz, f ); - return visitor; - } - } - } public static class Square { final double side; @@ -62,18 +39,32 @@ public Rectangle( double weidht, double height ) { } } - static Function areaVisitor = new LambdaVisitor() - .on(Square.class).then( s -> s.side * s.side ) - .on(Circle.class).then( c -> Math.PI * c.radius * c.radius ) - .on(Rectangle.class).then( r -> r.height * r.weidht ); + @org.derive4j.Data + // see the generated "Elements" class for constructors (https://gist.github.com/jbgi/393f621decdeb1374b1f3356b2d140b6) + interface Element { + // we could have used the same visitor interface as in gof visitor... but let's go with an equivalent catamorphism definition: + T match( Function squareElement, + Function circleElement, + Function rectangleElement ); + } + + + // like with the visitor pattern, pattern matching synthax ensure that all 3 cases are handled: + + static Function areaVisitor = element -> element.match( + s -> s.side * s.side, + c -> Math.PI * c.radius * c.radius, + r -> r.height * r.weidht + ); - static Function perimeterVisitor = new LambdaVisitor() - .on(Square.class).then( s -> 4 * s.side ) - .on(Circle.class).then( c -> 2 * Math.PI * c.radius ) - .on(Rectangle.class).then( r -> 2 * r.height + 2 * r.weidht ); + // or using the equivalent syntax generated by derive4j: + static Function perimeterVisitor = Elements.cases() + .squareElement( s -> 4 * s.side ) + .circleElement( c -> 2 * Math.PI * c.radius ) + .rectangleElement( r -> 2 * r.height + 2 * r.weidht ); public static void main( String[] args ) { - List figures = Arrays.asList( new Circle( 4 ), new Square( 5 ), new Rectangle( 6, 7 ) ); + List figures = Arrays.asList( circleElement(new Circle( 4 )), squareElement(new Square( 5 )), rectangleElement(new Rectangle( 6, 7 )) ); double totalArea = figures.stream().map( areaVisitor ).reduce( 0.0, (v1, v2) -> v1 + v2 ); System.out.println("Total area = " + totalArea);