define

Chain of responsibility pattern is to create multiple processes the request object, the object of a chain in a certain order, (like the list, a pointer to find successors) before an object holds the next object instance reference, you can find an object, under the request from the head start, passing on the chain, who can deal with as soon as processing, request to end, All the way to the end of the chain. Just like the company’s approval of leave, sometimes it needs to be approved by the department head, and sometimes it needs to be approved by HR. For example, filters in the Struct framework are also applications of the chain of responsibility pattern. The chain of responsibility model can be used to process orders with different priorities in an ERP system. Orders can be divided into single booking in advance, for example, ordinary orders and urgent delivery of orders, to create different processor to carry on the processing of different types of orders, and then according to the priority of the processor chain of responsibility, all orders through the chain of responsibility, according to the order of the different grade, only the corresponding level of the processor to handle corresponding levels of order, It’s the same as having access.

UML

The chain of responsibility pattern involves two roles: Abstract Handler: Holds an object reference to the next Handler, defines an interface to process requests, and provides methods to set up the next Handler. ConcreteHandler: implements or inherits abstract processor roles.

Chain of responsibility for orders

As mentioned above, for the processing of three orders with different priorities, we need to define at least one abstract processor, then define three concrete processors, and form the responsibility chain of these three processors according to priority, and then in the business logic, give the order to the responsibility chain for processing.

Abstract processor

/** * public abstract class Handler {private Handler nextHandler; private Integer priority; public Handler(Integer priority) { this.priority = priority; } public voidsetHandler(Handler nextHandler) { this.nextHandler = nextHandler; } /** * handles the delivery of the order request, calling solveOrder() if it is at the current level, otherwise passing to the upper level. * @param order */ public final void handleOrder(Order order) {if (order == null || order.getOrderId() == null) {
            throw new RuntimeException("Order information is empty and cannot be processed");
        }
        if (order.getPriority() == null) {
            throw new IllegalArgumentException("Order"+order.getOrderId()+"No processing level is set");
        }
        if (order.getPriority().equals(this.priority)) {
            this.solveOrder(order);
        } else {
            if(this.nextHandler ! = null) { System.out.println(this.getClass().getName()+"Unable to process order"+order.getOrderId()+", passed to a higher-level handler.");
                nextHandler.handleOrder(order);
            } else {
                throw new RuntimeException("No Handler can process the current order level"); }} public void solveOrder(Order Order); }Copy the code
Public class Order {// Order id private Long orderId; // Order priority private Integer priority; public LonggetOrderId() {
        return orderId;
    }

    public void setOrderId(Long orderId) {
        this.orderId = orderId;
    }

    public Integer getPriority() {
        return priority;
    }

    public void setPriority(Integer priority) { this.priority = priority; }}Copy the code

Assume that the order contains the order ID and order priority. In the abstract processor, we define the next processor nextHandler, and define the set method to set, and then define a unified method to process the order, the subclass call is this entry, verify the validity of the order information, and determine the priority of the order, whether the current processor can process. If it can’t handle it, pass it to the next handler, and throw an exception if there isn’t one.

Concrete processor

Public class OrderHandlerMap {public static Map<Integer, Handler> Map = new HashMap<>(); }Copy the code
/** * Pre-order processor, */ @Component Public Class PreSellOrderHandler extends Handler implements InitializingBean{/** * Set the priority of orders that can be processed to 1 */PreSellOrderHandler() {
        super(1);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"Start processing orders"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() { OrderHandlerMap.map.put(1,this); }} /** * Normal order processor, Component Public Class NormalOrderHandler extends Handler Implements InitializingBean{/** * Sets the priority of orders that can be processed =2 * /NormalOrderHandler() {
        super(2);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"Start processing orders"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() { OrderHandlerMap.map.put(2, this); }} /** * Emergency shipping order handler, Set priority =3 */ @Component Public Class UrgentOrderHandler extends Handler implements InitializingBean{/** * Set the priority of orders that can be processed to 3 */UrgentOrderHandler() {
        super(3);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"Start processing orders"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() { OrderHandlerMap.map.put(3,this); }}Copy the code

Three order handlers with different priorities are defined and a processor object is instantiated into the Map container when the Spring container starts.

Order processing class

Suppose an order comes in now, what about the chain of responsibility?

@ RunWith (SpringJUnit4ClassRunner. Class) @ SpringBootTest (classes = Application. The class) / / specified spring - the boot startup class public class OrderHandlerTest1 { @Test public voidtest() {
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("No processors are registered in Spring"); } // Get the lowest priority Handler Handler = null;for (Map.Entry<Integer,Handler> entry : handlerMap.entrySet()) {
            handler = entry.getValue();
            if(handler ! =null) {break; Order preSellOrder = new Order(); preSellOrder.setOrderId(123L); preSellOrder.setPriority(1); handler.handleOrder(preSellOrder); Order normalOrder = new Order(); normalOrder.setOrderId(456L); normalOrder.setPriority(2); handler.handleOrder(normalOrder); Order urgentOrder = new Order(); urgentOrder.setOrderId(789L); urgentOrder.setPriority(3); handler.handleOrder(urgentOrder); Order unknownOrder = new Order(); unknownOrder.setOrderId(111L); unknownOrder.setPriority(9); handler.handleOrder(unknownOrder); } @Before public voidbefore(){
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("No processors are registered in Spring"); } List< map.entry <Integer,Handler>> List = new ArrayList<>(handlermap.entryset ()); Collections.sort(list, new Comparator<Map.Entry<Integer, Handler>>() { @Override public int compare(Map.Entry<Integer, Handler> o1, Map.Entry<Integer, Handler> o2) {returno1.getKey().compareTo(o2.getKey()); }}); List<Integer> keys = new ArrayList<>(handlerMap.keySet()); Collections.sort(keys); // Set the higher level of the processor, keys are already sorted by priorityfor (int i=0; i<keys.size(); i++) {
            Integer key = keys.get(i);
            Handler handler = handlerMap.get(key);
            if (i < keys.size()-1) {
                Integer nextKey = keys.get(i + 1);
                if(nextKey ! = null) { Handler nextHandler = handlerMap.get(nextKey); handler.setHandler(nextHandler); } } } } }Copy the code

Before we test, the processors in the Map form a chain of processor responsibilities in order of priority, and we need to set who the current processor will process next. Then in the test method, four orders of different priorities are created, which are handed to the first processor in the chain of responsibility for processing, but only the corresponding level of processor can really process the order. The first processor can process order 123, the second processor can process order 456, and the third processor can process order 789. Because the order 111 level is unknown, there is no processor to process, so an error is reported.