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..d17970f 100644 --- a/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java +++ b/src/main/java/org/mfusco/fromgoftolambda/examples/visitor/VisitorLambda.java @@ -4,81 +4,118 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; -public class VisitorLambda { +public class VisitorLambda +{ - public static class LambdaVisitor implements Function { - private Map, Function> fMap = new HashMap<>(); + public static class LambdaVisitor implements Function> + { + Map, NonTotalFunction> 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 ); - } + public LambdaVisitor with(NonTotalFunction f) + { + fMap.put(f.clazz, f); + return this; + } - static class Acceptor { - private final LambdaVisitor visitor; - private final Class clazz; + @Override + public Optional apply(Object o) + { + return fMap.getOrDefault(o.getClass(), NonTotalFunction.empty()).apply(o); + } + } - public Acceptor( LambdaVisitor visitor, Class clazz ) { - this.visitor = visitor; - this.clazz = clazz; - } + public static class NonTotalFunction implements Function> + { + public final Class clazz; + private final Function fun; - public LambdaVisitor then(Function f) { - visitor.fMap.put( clazz, f ); - return visitor; - } - } + public NonTotalFunction(Class clazz, Function fun) + { + this.clazz = clazz; + this.fun = fun; } - public static class Square { - final double side; + @SuppressWarnings("rawtypes") + private static final NonTotalFunction EMPTY = new Empty(); + + @SuppressWarnings("unchecked") + @Override + public Optional apply(Object o) + { + if (clazz.isAssignableFrom(o.getClass())) + return Optional.of(fun.apply((T) o)); + else + return Optional.empty(); + } - public Square(double side) { - this.side = side; - } + public static NonTotalFunction of(Class cl, Function fu) + { + return new NonTotalFunction<>(cl, fu); } - public static class Circle { - final double radius; + @SuppressWarnings("unchecked") + public static NonTotalFunction empty() + { + return EMPTY; + } - public Circle(double radius) { - this.radius = radius; - } + static class Empty extends NonTotalFunction + { + public Empty() + { + super(Void.TYPE, (Void x) -> null); + } } + } - public static class Rectangle { - final double weidht; - final double height; + public static class Square + { + final double side; - public Rectangle( double weidht, double height ) { - this.weidht = weidht; - this.height = height; - } + public Square(double side) + { + this.side = side; } + } - 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 ); - - 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 ); + public static class Circle + { + final double radius; - public static void main( String[] args ) { - List figures = Arrays.asList( new Circle( 4 ), new Square( 5 ), new Rectangle( 6, 7 ) ); + public Circle(double radius) + { + this.radius = radius; + } + } - double totalArea = figures.stream().map( areaVisitor ).reduce( 0.0, (v1, v2) -> v1 + v2 ); - System.out.println("Total area = " + totalArea); + public static class Rectangle + { + final double width; + final double height; - double totalPerimeter = figures.stream().map( perimeterVisitor ).reduce( 0.0, (v1, v2) -> v1 + v2 ); - System.out.println("Total perimeter = " + totalPerimeter); + public Rectangle(double width, double height) + { + this.width = width; + this.height = height; } -} + } + + static Function> areaVisitor = new LambdaVisitor() + .with(NonTotalFunction.of(Square.class, s -> s.side * s.side)) + .with(NonTotalFunction.of(Circle.class, c -> Math.PI * c.radius * c.radius)) + .with(NonTotalFunction.of(Rectangle.class, r -> r.height * r.width)); + + static Function> perimeterVisitor = new LambdaVisitor() + .with(NonTotalFunction.of(Square.class, s -> 4 * s.side)) + .with(NonTotalFunction.of(Circle.class, c -> 2 * Math.PI * c.radius)); + + public static void main(String[] args) + { + List figures = Arrays.asList(new Circle(4), new Square(5), new Rectangle(6, 7)); + figures.forEach(o -> System.out.println(areaVisitor.apply(o))); + figures.forEach(o -> System.out.println(perimeterVisitor.apply(o))); + } +} \ No newline at end of file