一文搞懂責任鏈模式

定義

責任鏈模式就是建立多個處理請求的對象,這些對象按照某種順序組成一條鏈,(就像鏈表同樣,有個指針能夠找到後繼)前一個對象保存了下一個對象的實例引用,能夠找到下一個對象,請求從頭部開始,在這條鏈上傳遞,誰能處理就當即處理,請求結束,直到鏈的結尾。 就像公司審批請假同樣,有時候須要部門主管審批完就能夠,有時候還須要hr審批經過才行。好比struct框架中的過濾器,也是責任鏈模式的應用。
ERP系統中不一樣優先級的訂單處理就能夠用責任鏈模式。例如訂單分爲預售提早單,普通訂單以及緊急發貨的訂單,建立不一樣的處理器進行不一樣類型訂單的處理,而後按照優先級將這些處理器組成責任鏈,全部訂單都通過這條責任鏈,根據訂單等級的不一樣,只有對應等級的處理器才能處理對應等級的訂單,這就跟有沒有權限是一個道理。spring

UML

責任鏈模式涉及兩個角色:
抽象處理器角色(Handler):持有下一個處理器的對象引用,定義了處理請求的接口,提供了設置下一個處理器的方法。
具體處理器角色(ConcreteHandler):實現或者繼承抽象處理器角色。bash

訂單的責任鏈

按照如上所說,對三種優先級不一樣訂單的處理,咱們至少須要定義一個抽象處理器,而後定義三個具體處理器,將這三個處理器按優先級組成責任鏈,而後在業務邏輯中,將訂單交給責任鏈處理。框架

抽象處理器

/**
 * 抽象處理器角色
 */
public abstract class Handler {

    private Handler nextHandler;

    private Integer priority;

    public Handler(Integer priority) {
        this.priority = priority;
    }

    public void setHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    /**
     * 處理訂單請求的傳遞,若是是當前級別則調用solveOrder()方法處理,不然傳遞給上一級處理。
     * @param order
     */
    public final void handleOrder(Order order) {
        if (order == null || order.getOrderId() == null) {
            throw new RuntimeException("訂單信息爲空,沒法處理");
        }
        if (order.getPriority() == null) {
            throw new IllegalArgumentException("訂單"+order.getOrderId()+"沒有設置處理級別");
        }
        if (order.getPriority().equals(this.priority)) {
            this.solveOrder(order);
        } else {
            if (this.nextHandler != null) {
                System.out.println(this.getClass().getName()+"沒法處理訂單"+order.getOrderId()+",傳遞給高一級的handler處理");
                nextHandler.handleOrder(order);
            } else {
                throw new RuntimeException("沒有Handler可以處理當前等級的訂單");
            }
        }
    }

    /**
     * 定義處理訂單的方法,由子類實現,處理不一樣等級的訂單
     */
    public abstract void solveOrder(Order order);
}
複製代碼
public class Order {

    //訂單id
    private Long orderId;

    //訂單優先級
    private Integer priority;

    public Long getOrderId() {
        return orderId;
    }

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

    public Integer getPriority() {
        return priority;
    }

    public void setPriority(Integer priority) {
        this.priority = priority;
    }
}
複製代碼

假設訂單中包含訂單id和訂單優先級。
在抽象處理器中,咱們定義了下一個處理器nextHandler,並定義set方法進行設置,而後定義了一個處理訂單的統一方法,子類調用時都是這個入口,對訂單信息進行合法性校驗,並判斷訂單的優先級,當前處理器可否處理,若是沒法處理就交給下一個處理器,若是沒有下一個處理器就拋出異常。ide

具體處理器

/**
 * 定義一個Map容器,保存全部訂單處理器
 */
public class OrderHandlerMap {

    public static Map<Integer, Handler> map = new HashMap<>();

}
複製代碼
/**
 * 預售訂單的處理器,預售訂單的優先級最低
 */
@Component
public class PreSellOrderHandler extends Handler implements InitializingBean{

    /**
     * 設置可以處理的訂單優先級=1
     */
    PreSellOrderHandler() {
        super(1);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"開始處理訂單"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(1,this);
    }
}

/**
 * 正常訂單的處理器,設置優先級爲2
 */
@Component
public class NormalOrderHandler extends Handler implements InitializingBean{

    /**
     * 設置可以處理的訂單優先級=2
     */
    NormalOrderHandler() {
        super(2);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"開始處理訂單"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(2, this);
    }
}

/**
 * 緊急發貨訂單的處理器,設置優先級最高=3
 */
@Component
public class UrgentOrderHandler extends Handler implements InitializingBean{

    /**
     * 設置可以處理的訂單優先級=3
     */
    UrgentOrderHandler() {
        super(3);
    }

    @Override
    public void solveOrder(Order order) {
        System.out.println(this.getClass().getName()+"開始處理訂單"+order.getOrderId());
    }

    @Override
    public void afterPropertiesSet() {
        OrderHandlerMap.map.put(3,this);
    }
}
複製代碼

定義了三個優先級不一樣的訂單處理器,並在spring容器啓動時實例化一個處理器對象放到Map容器中。spring-boot

訂單處理類

假設如今來了一個訂單,責任鏈要怎麼處理呢?測試

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes=Application.class)// 指定spring-boot的啓動類
public class OrderHandlerTest1 {

    @Test
    public void test() {
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("spring中沒有註冊任何處理器");
        }
        //獲取最低優先級的處理器
        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 void before(){
        Map<Integer, Handler> handlerMap = OrderHandlerMap.map;
        if (handlerMap.isEmpty()) {
            throw new RuntimeException("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) {
                return o1.getKey().compareTo(o2.getKey());
            }
        });
        List<Integer> keys = new ArrayList<>(handlerMap.keySet());
        Collections.sort(keys);
        //設置處理器的更高一級的處理器,keys已是按照優先級排好序的
        for (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);
                }
            }
        }
    }
}
複製代碼

咱們在測試以前,先將Map中的處理器組成一個按照優先級排列的處理器責任鏈,並須要設置當前處理器的下一個處理是誰。而後在測試方法中建立了四種不一樣優先級的訂單,都交給責任鏈的第一個處理器進行處理,可是真正可以處理該訂單的只有對應等級的處理器。運行結果以下,第一個處理器就能夠處理訂單123,第二個處理器處理訂單456,第三個處理器處理訂單789,因爲訂單111等級未知,沒有處理器能夠處理,就報錯。ui

相關文章
相關標籤/搜索