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;
}
}
}
Consumer.andThen()
for clues on how it might be approached – Mccammon