一切拋開業務的設計,都是扯淡!在專案中有個我們會對多個介面進行多業務邏輯判斷,專案開始工期緊,所以先以實作功能為主,最近打算優化一番,一開始的代碼是這樣的
public void checkProjectAdd(List<OrderDetail> list) {
if (!CollectionUtils.isEmpty(list)) {
orderService.check(list);
stockService.check(list);
orderAddress.check(list);
userScoreService.check(list);
activityService.check(list);
this.check();
}
excute();
}
雖然對檢查類的方法做了簡單的封裝,但在好多地方可能會存在重復的判斷,比如訂單提交,加入購物車等等,冗余代碼隨處可見,且不易擴展,在此情形下,廢話不多說,準備開干,先來分析分析業務,因為我們的各個檢查介面的處理原則是要保證順序性的,而在檢查的程序中可能根據商品提交引數而實質去動態改變list引數中的內容,比如一個庫存當兩個賣,用戶會員等級結合實際商品數判斷能否享受折扣等等,所以每一級的檢查或手動處理值都是要求檢查類代碼執行順序,思前想后,想起曾在閱讀mybatis原始碼時覺得其設計的plugins模式很適合此類場景,于是決定使用《責任鏈模式》來進行這一次代碼的優化,
首先簡單介紹一下什么是責任鏈,說到鏈,大家就能想到鏈表,這里我們只說最簡單的鏈表(單向鏈表)

單向鏈表就是當前物件記憶體儲著下一個物件的參考地址,責任鏈模式的概念也描述下:
責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者物件的鏈,這種模式給予請求的型別,對請求的發送者和接收者進行解耦,這種型別的設計模式屬于行為型模式,在這種模式中,通常每個接收者都包含對另一個接收者的參考,如果一個物件不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推,
**概念都是標準,一般都很難理解是什么意思,我們拿圖說事
**

這每一層都是大哥,想要跨過難關還是不太容易呀,但是沒辦法為了要干真正的實事還是要一關一關闖的,接下來我們要開始進行包裝,AOP大家都知道(面向切面),既然我們最終的提交方法是excute,那切面就是excute了,在切面之前如何執行自定義的Interceptor(攔截器)呢?這里我是用的是jdk動態代理模式,動態代理,不太了解的看這里(JDK動態代理),使用動態代理的好處是我們可以對成百上千個已知與將來可能要撰寫的介面進行包裝,比如我的訂單提交事件叫做submitOrder,加入購車addCart,我都可以通過我的代理模式對這些介面進行包裝,在代理模式中我規定好Interceptor,這樣就能統一了

通過一級一級的代理模型,最終我們才能真正呼叫到IOrderService的具體實作上,廢話不多說,開始擼代碼
首先定義好我們自己攔截器類
public interface Interceptor {
Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException;
}
接下來代理工廠:
public class ProxyFactory implements InvocationHandler {
private Object target;
private Interceptor interceptor;
private ProxyFactory(Object target, Interceptor interceptor) {
this.target = target;
this.interceptor = interceptor;
}
public static Object wrap(Object target, Interceptor filter) {
ProxyFactory proxyFactory = new ProxyFactory(target, filter);
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(), proxyFactory);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Invocation invocation = new Invocation(target, method, args);
return interceptor.intercept(invocation);
}
}
代理工廠主要就是對目標物件target進行包裝,這里的target可能是原物件,也有可能是包裝過后代理物件二次包裝代理,簡單來說是這樣,我們的IOrderService中的submitOrder方法,在托管給JDK動態代理后,為了實作責任鏈的鏈式原則,我們會基于此物件再次呼叫wrap方法進行二次包裝,將我們的各式各樣的攔截器一層一層的包裝上去,這樣處理成上一級參考下一級的鏈式關系,
接下來定義我們具體都又那些攔截器大哥
public class TodoInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(" todo something ");
Object result = invocation.proceed();
System.out.println(" to do end something ");
return result;
}
}
public class LogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException {
System.out.println(" do log ");
Object result = invocation.proceed();
System.out.println(" do log ");
return result;
}
}
兩位攔路大哥已再此,接下來我們吧攔路大哥們放入工廠進行包裝
@Override
public void checkSubmitOrder() {
IOrderService orderService = new OrderService();
orderService = (IOrderService) ProxyFactory.wrap(orderService, new LogInterceptor());
orderService = (IOrderService) ProxyFactory.wrap(orderService, new TodoInterceptor());
orderService.submitOrder();
}
代碼執行效果如下

例子挺簡單的,主要是說明責任鏈可以使用的場景,結合此責任鏈的擴展就非常多了,例如我把攔截器統一交給spring 托管,在每個檢查方法上自定義注解,標記需要執行的攔截器,在AOP切面掃描業務方法時,判斷是否存在此類責任鏈的攔截注解,有的話則執行業務判斷,這樣子就統一了業務檢查代碼的封裝,再也不用再每行代碼里寫那些重復的chek()了,介于篇幅,就不在過多介紹了,有興趣可以私聊我,
來源: https://www.cnblogs.com/doNetTom/p/13685988.html
歡迎關注公眾號 【碼農開花】一起學習成長
我會一直分享Java干貨,也會分享免費的學習資料課程和面試寶典
回復:【計算機】【設計模式】【面試】有驚喜哦
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/242221.html
標籤:其他
上一篇:分布式事務概述及大廠通用解決方案
