深入了解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 進(jìn)去。
類圖

代碼實現(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é)果集進(jìn)行處理
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進(jìn)行controller層單元測試 事務(wù)自動回滾的完整案例
這篇文章主要介紹了使用MockMvc進(jìn)行controller層單元測試 事務(wù)自動回滾的完整案例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06
Java中xxl-job實現(xiàn)分片廣播任務(wù)的示例
本文主要介紹了Java中xxl-job實現(xiàn)分片廣播任務(wù)的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
Springboot Mybatis-Plus數(shù)據(jù)庫單元測試實戰(zhàn)(三種方式)
這篇文章主要介紹了Springboot Mybatis-Plus數(shù)據(jù)庫單元測試實戰(zhàn)(三種方式),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Spring?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

