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