javadesign-patternslambdajava-8chain-of-responsibility

Chain of responsibility - lambda function implementation


How would you implement Chain of Responsibility pattern using Lambda in Java 8?


I only found a paragraph in this article:

Chain of responsibility

A lambda that may or may not delegate to another lambda, which may or may not delegate to another lambda, ad infinitum. (How to get the ‘next’ reference into the lambda is left as an exercise for the reader.)


Solution

  • I have adapted the java example from the wikipedia article:

    In this example we have different roles, each having a fixed purchasing limit and a successor. Every time a user in a role receives a purchase request that exceeds his or her limit, the request is passed to his or her successor.

    A builder allow to build a chain of handler :

    public class Main {
        public static void main(String[] args) {
            final double base = 500;
            ChainBuilder<PurchaseRequest> chainBuilder = ChainBuilder.chainBuilder();
            Chain<PurchaseRequest> chain = chainBuilder
                    .first(request -> {
                        if (request.getAmount() < base * 10) {
                            System.out.println("Manager will approve $" + request.getAmount());
                            return true;
                        }
                        return false;
                    })
                    .successor(request -> {
                        if (request.getAmount() < base * 20) {
                            System.out.println("Director will approve $" + request.getAmount());
                            return true;
                        }
                        return false;
                    })
                    .successor(request -> {
                        if (request.getAmount() < base * 50) {
                            System.out.println("President will approve $" + request.getAmount());
                        } else {
                            System.out.println("Your request for $" + request.getAmount() + " needs a board meeting!");
                        }
                        return true;
                    }).build();
    
            chain.handle(new PurchaseRequest(1000)); // manager
            chain.handle(new PurchaseRequest(9000)); // director
            chain.handle(new PurchaseRequest(23000)); // president
            chain.handle(new PurchaseRequest(100000)); // board
        }
    
        private static class PurchaseRequest {
            private final double amount;
    
            private PurchaseRequest(double amount) {
                this.amount = amount;
            }
    
            public double getAmount() {
                return amount;
            }
        }
    }
    

    The lambda implements the functional interface Handler. true is return if the request was handled, false if the request should be processed by the successor:

    public interface Handler<T> {
        boolean handle(T t);
    }
    

    The Chain is a basic a consumer-like interface:

    public interface Chain<T> {
        void handle(T t);
    }
    

    the builder implementation:

    public class ChainBuilder<T> {
        public static <T> ChainBuilder<T> chainBuilder() {
            return new ChainBuilder<>();
        }
    
        private HandlerImpl<T> first;
    
        private ChainBuilder() {
        }
    
        public SuccessorBuilder first(Handler<T> handler) {
            first = new HandlerImpl<>(handler);
            return new SuccessorBuilder(first);
        }
    
        public class SuccessorBuilder {
            private HandlerImpl<T> current;
    
            private SuccessorBuilder(HandlerImpl<T> current) {
                this.current = current;
            }
    
            public SuccessorBuilder successor(Handler<T> successor) {
                HandlerImpl<T> successorWrapper = new HandlerImpl<>(successor);
                current.setSuccessor(successorWrapper);
                current = successorWrapper;
                return this;
            }
    
            public Chain<T> build() {
                return new ChainImpl<T>(first);
            }
        }
    
        private static class ChainImpl<T> implements Chain<T> {
            private final Handler<T> first;
    
            public ChainImpl(Handler<T> first) {
                this.first = first;
            }
    
            @Override
            public void handle(T t) {
                first.handle(t);
            }
        }
    
        private static class HandlerImpl<T> implements Handler<T> {
            private final Handler<T> delegate;
            private Handler<T> successor;
    
            public HandlerImpl(Handler<T> delegate) {
                this.delegate = delegate;
            }
    
            private void setSuccessor(HandlerImpl<T> successor) {
                this.successor = successor;
            }
    
            @Override
            public boolean handle(T t) {
                if (delegate.handle(t)) {
                    return true;
                }
                else if (successor != null) {
                    return successor.handle(t);
                }
                return false;
            }
        }
    }