深入了解Java設(shè)計模式之職責(zé)鏈模式
定義
使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接受者之間的耦合關(guān)系,將這個對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。
解決的問題
請求和處理分開、實現(xiàn)解耦、提高系統(tǒng)的靈活性
可以動態(tài)的調(diào)整請求的鏈條,增加系統(tǒng)靈活性
核心要點
職責(zé)鏈模式每個執(zhí)行者都包含了另一個執(zhí)行者的引用。如果一個對象不能處理該請求,會把請求傳遞給下一個執(zhí)行者。
客戶端需要動態(tài)的調(diào)整,執(zhí)行者的上下級。
Handler 里面聚合它自己,在 HandlerRequest 里判斷是否合適,如果沒達(dá)到條件則向下傳遞,向誰傳遞之前 set 進去。
類圖
代碼實現(xiàn)
抽象父類
/** * 處理請求的抽象類 * * @author Promsing(張有博) * @version 1.0.0 * @since 2022/9/7 - 9:29 */ public abstract class Handler { //維持一個下一個執(zhí)行者的引用 protected Handler handler; protected void setHandler(Handler handler) { this.handler = handler; } //處理請求的抽象方法 public abstract void processRequest(int request); }
執(zhí)行者-三個
/** * 只處理數(shù)字1-10 * * @author Promsing(張有博) * @version 1.0.0 * @since 2022/9/7 - 9:31 */ public class ConcreteHandlerA extends Handler{ @Override public void processRequest(int request) { if (request>=0 && request<10 ){ System.out.println("ConcreteHandlerA已經(jīng)處理完畢了 "+request); return; } if (handler!=null){ //下一位處理 handler.processRequest(request); } } } /** * 只處理數(shù)字10-20 * * @author Promsing(張有博) * @version 1.0.0 * @since 2022/9/7 - 9:31 */ public class ConcreteHandlerB extends Handler{ @Override public void processRequest(int request) { if (request>=10 && request<20 ){ System.out.println("ConcreteHandlerB已經(jīng)處理完畢了 "+request); return; } if (handler!=null){ //下一位處理 handler.processRequest(request); } } } /** *只處理數(shù)字30+ * * @author Promsing(張有博) * @version 1.0.0 * @since 2022/9/7 - 9:31 */ public class ConcreteHandlerC extends Handler{ @Override public void processRequest(int request) { if (request>=30 ){ System.out.println("ConcreteHandlerC已經(jīng)處理完畢了 "+request); return; } if (handler!=null){ //下一位處理 handler.processRequest(request); } } }
客戶端
public class Main { public static void main(String[] args) { //創(chuàng)建執(zhí)行者 Handler h1=new ConcreteHandlerA(); Handler h2=new ConcreteHandlerB(); Handler h3=new ConcreteHandlerC(); //設(shè)置向下級的順序,可根據(jù)配置動態(tài)設(shè)置上下級 h1.setHandler(h2); h2.setHandler(h3); int[] requests={8,11,23,50,7,19,28,40}; //循環(huán)處理請求,不同的數(shù)值,交給不同的執(zhí)行者 for (int request : requests) { h1.processRequest(request); } } }
拓展
SpringMVC中DispatchServlet使用職責(zé)鏈
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request;//請求 HandlerExecutionChain mappedHandler = null;//執(zhí)行鏈 try { ModelAndView mv = null; Exception dispatchException = null; try { // Determine handler for the current request. mappedHandler = getHandler(processedRequest); //根據(jù)請求-獲得執(zhí)行鏈 //判斷mappedHandler是否為空,空:404 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 確定當(dāng)前請求的處理程序適配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //職責(zé)鏈的前置攔截 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //執(zhí)行handler方法-controller mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //職責(zé)鏈的后置攔截 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //對結(jié)果集進行處理 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //執(zhí)行完成了攔截器 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } finally { //資源釋放 } }
攔截器的方法
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); //獲得攔截器 if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) {//循環(huán)遍歷執(zhí)行前置攔截 HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); //獲得攔截器 if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { //循環(huán)遍歷執(zhí)行后置攔截 HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); //獲得攔截器 if (!ObjectUtils.isEmpty(interceptors)) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { //循環(huán)遍歷執(zhí)行完成攔截 interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } }
應(yīng)用場景
1、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定。
2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
3、可動態(tài)指定一組對象處理請求。
4、比如:JS 中的事件冒泡,JAVA WEB 中 Apache Tomcat 對 Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter。
到此這篇關(guān)于深入了解Java設(shè)計模式之職責(zé)鏈模式的文章就介紹到這了,更多相關(guān)Java職責(zé)鏈模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用MockMvc進行controller層單元測試 事務(wù)自動回滾的完整案例
這篇文章主要介紹了使用MockMvc進行controller層單元測試 事務(wù)自動回滾的完整案例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Java中xxl-job實現(xiàn)分片廣播任務(wù)的示例
本文主要介紹了Java中xxl-job實現(xiàn)分片廣播任務(wù)的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Springboot Mybatis-Plus數(shù)據(jù)庫單元測試實戰(zhàn)(三種方式)
這篇文章主要介紹了Springboot Mybatis-Plus數(shù)據(jù)庫單元測試實戰(zhàn)(三種方式),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Spring?Boot?3中一套可以直接用于生產(chǎn)環(huán)境的Log4J2日志配置詳解
Log4J2是Apache Log4j的升級版,參考了logback的一些優(yōu)秀的設(shè)計,并且修復(fù)了一些問題,因此帶來了一些重大的提升,這篇文章主要介紹了Spring?Boot?3中一套可以直接用于生產(chǎn)環(huán)境的Log4J2日志配置,需要的朋友可以參考下2023-12-12