摘要:責(zé)任鏈模式屬于行為型模式的一種,將請求沿著一條鏈傳遞,直到該鏈上的某個對象處理它為止。責(zé)任鏈模式通過將請求和處理分離開來,以進(jìn)行解耦。源碼分析我們經(jīng)常使用的就使用到了責(zé)任鏈模式,創(chuàng)建一個除了要在應(yīng)用中做相應(yīng)配置外,還需要實(shí)現(xiàn)接口。
概述責(zé)任鏈模式(Chain Of Responsibility Pattern)屬于行為型模式的一種,將請求沿著一條鏈傳遞,直到該鏈上的某個對象處理它為止。
定義如下:一個請求有多個對象來處理,這些對象形成一條鏈,根據(jù)條件確定具體由誰來處理,如果當(dāng)前對象不能處理則傳遞給該鏈中的下一個對象,直到有對象處理它為止。責(zé)任鏈模式通過將請求和處理分離開來,以進(jìn)行解耦。職責(zé)鏈模式結(jié)構(gòu)的核心在于引入了一個抽象處理者。
UML結(jié)構(gòu)圖
模式結(jié)構(gòu)
Handler(抽象處理者): 定義一個處理請求的接口,提供對后續(xù)處理者的引用
ConcreteHandler(具體處理者): 抽象處理者的子類,處理用戶請求,可選將請求處理掉還是傳給下家;在具體處理者中可以訪問鏈中下一個對象,以便請求的轉(zhuǎn)發(fā)。
案例UML圖如下:
1.定義AbstractHandler(抽象處理者),使子類形成一條鏈
public abstract class AbstractHandler { private AbstractHandler handler; public abstract void handleRequest(String condition); public AbstractHandler getHandler() { return handler; } public void setHandler(AbstractHandler handler) { this.handler = handler; } }
2.創(chuàng)建若干個ConcreteHandler(具體處理者)繼承AbstractHandler,在當(dāng)前處理者對象無法處理時,將執(zhí)行權(quán)傳給下一個處理者對象
public class ConcreteHandlerA extends AbstractHandler { @Override public void handleRequest(String condition) { if (condition.equals("A")) { System.out.println("ConcreteHandlerA處理"); } else { System.out.println("ConcreteHandlerA不處理,由其他的Handler處理"); super.getHandler().handleRequest(condition); } } } public class ConcreteHandlerB extends AbstractHandler { @Override public void handleRequest(String condition) { if (condition.equals("B")) { System.out.println("ConcreteHandlerB處理"); } else { System.out.println("ConcreteHandlerB不處理,由其他的Handler處理"); super.getHandler().handleRequest(condition); } } } public class ConcreteHandlerZ extends AbstractHandler { @Override public void handleRequest(String condition) { //一般是最后一個處理者 System.out.println("ConcreteHandlerZ處理"); } }
3.創(chuàng)建ChainClient(測試類)
public class ChainClient { public static void main(String[] args) { AbstractHandler handlerA = new ConcreteHandlerA(); AbstractHandler handlerB = new ConcreteHandlerB(); AbstractHandler handlerZ = new ConcreteHandlerZ(); // 如A處理不掉轉(zhuǎn)交給B handlerA.setHandler(handlerB); handlerB.setHandler(handlerZ); handlerA.handleRequest("Z"); } }
4.運(yùn)行效果
----------------------handleRequest("A")------------------------- ConcreteHandlerA處理 ----------------------handleRequest("B")------------------------- ConcreteHandlerA不處理,由其他的Handler處理 ConcreteHandlerB處理 ----------------------handleRequest("Z")------------------------- ConcreteHandlerA不處理,由其他的Handler處理 ConcreteHandlerB不處理,由其他的Handler處理 ConcreteHandlerZ處理
可以看出,客戶端創(chuàng)建了三個處理者對象,并指定第一個處理者對象的下家是第二個處理者對象,第二個處理者對象的下家是第三個處理者對象。然后客戶端將請求傳遞給第一個處理者對象。
由于本示例的傳遞邏輯非常簡單:只要有下家,就傳給下家處理;如果沒有下家,就自行處理。因此,第一個處理者對象接到請求后,會將請求傳遞給第二個處理者對象。由于第二個處理者對象沒有下家,于是自行處理請求。活動時序圖如下所示。
純與不純純:要么承擔(dān)全部責(zé)任,要么將責(zé)任推給下家,不允許出現(xiàn)某一個具體處理者對象在承擔(dān)了一部分或全部責(zé)任后又將責(zé)任向下傳遞的情況。
不純:允許某個請求被一個具體處理者部分處理后再向下傳遞,或者一個具體處理者處理完某請求后其后繼處理者可以繼續(xù)處理該請求,而且一個請求可以最終不被任何處理者對象所接收。
Filter源碼分析我們經(jīng)常使用的Filter就使用到了責(zé)任鏈模式,創(chuàng)建一個Filter除了要在應(yīng)用中做相應(yīng)配置外,還需要實(shí)現(xiàn)javax.servlet.Filter接口。
@Configuration public class MyFilter implements Filter { private final static Logger LOGGER = LoggerFactory.getLogger(MyFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { LOGGER.info("init"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { LOGGER.info("doFilter"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { LOGGER.info("destroy"); } }
使用DEBUG模式所看到的結(jié)果如下:
Filter 集
在源碼ApplicationFilterChain中,定義了一個ApplicationFilterConfig的數(shù)組來存放所有的Filter,使之形成鏈狀
public final class ApplicationFilterChain implements FilterChain { // 擴(kuò)容規(guī)則 public static final int INCREMENT = 10; // Filter集,默認(rèn)大小為 0 個 private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; }
ApplicationFilterConfig 裝載規(guī)則
在應(yīng)用首次啟動時,會自動實(shí)例化對象,并從web應(yīng)用中讀取配置的Filter的信息,然后裝進(jìn)該容器。
public final class ApplicationFilterConfig implements FilterConfig, Serializable { // 省略代碼... }
ApplicationFilterConfig 擴(kuò)容規(guī)則
//將過濾器添加到在此鏈條中執(zhí)行的過濾器集合中。 void addFilter(ApplicationFilterConfig filterConfig) { // 防止多次添加相同的過濾器 for(ApplicationFilterConfig filter:filters) if(filter==filterConfig) return; if (n == filters.length) { // 定義一個在原基礎(chǔ)之上 +10 的新數(shù)組 ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; // 將源數(shù)組的元素拷貝到目標(biāo)數(shù)組中去 System.arraycopy(filters, 0, newFilters, 0, n); // 重新賦值 filters = newFilters; } //將變量filterConfig放入ApplicationFilterConfig數(shù)組中,并將當(dāng)前過濾器鏈里面擁有的過濾器數(shù)目+1 filters[n++] = filterConfig; }
addFilter 的使用
public static ApplicationFilterChain createFilterChain(ServletRequest request,Wrapper wrapper, Servlet servlet) { //如果沒有 servlet 要執(zhí)行,則返回null if (servlet == null) return null; // 創(chuàng)建和初始化過濾器鏈對象 ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; if (Globals.IS_SECURITY_ENABLED) { // 為了安全起見:不要回收 filterChain = new ApplicationFilterChain(); } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) { filterChain = new ApplicationFilterChain(); req.setFilterChain(filterChain); } } } else { // 調(diào)度程序在使用中 filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // 獲取過濾器上下文映射 StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // 如果沒有過濾器映射,就認(rèn)為當(dāng)前執(zhí)行完成 if ((filterMaps == null) || (filterMaps.length == 0)) return (filterChain); // 獲取匹配的過濾器映射信息 DispatcherType dispatcher = (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); String requestPath = null; Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); if (attribute != null){ requestPath = attribute.toString(); } String servletName = wrapper.getName(); // 將相關(guān)路徑映射的過濾器添加到此過濾器鏈中 for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersURL(filterMaps[i], requestPath)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // 添加與servlet名稱匹配的篩選器 for (int i = 0; i < filterMaps.length; i++) { if (!matchDispatcher(filterMaps[i] ,dispatcher)) { continue; } if (!matchFiltersServlet(filterMaps[i], servletName)) continue; ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMaps[i].getFilterName()); if (filterConfig == null) { // FIXME - log configuration problem continue; } filterChain.addFilter(filterConfig); } // 返回完整的過濾器鏈 return filterChain; }
createFilterChain 的調(diào)用
final class StandardWrapperValve extends ValveBase { public final void invoke(Request request, Response response) throws IOException, ServletException { // 省略代碼... // 為這個請求創(chuàng)建過濾器鏈 ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet); // 省略代碼... filterChain.doFilter(request.getRequest(), response.getResponse()); } }
執(zhí)行流程
在StandardWrapperValue類的invoke()方法中調(diào)用ApplicationFilterChai類的createFilterChain()方法
在ApplicationFilterChai類的createFilterChain()方法中調(diào)用ApplicationFilterChain類的addFilter()方法
在ApplicationFilterChain類的addFilter()方法中給ApplicationFilterConfig數(shù)組賦值。
最后一步
在doFilter()方法中最后會調(diào)用一個internalDoFilter()方法,目的就是執(zhí)行ApplicationFilterChain中的全部過濾器,從代碼中可以發(fā)現(xiàn)它調(diào)用了doFilter,而在doFilter又會調(diào)用internalDoFilter 從而使所有的Filter都得以調(diào)用
private void internalDoFilter(ServletRequest request,ServletResponse response) throws IOException, ServletException { // 如果存在下一個,繼續(xù)調(diào)用下一個過濾器 if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++]; try { Filter filter = filterConfig.getFilter(); if (request.isAsyncSupported() && "false".equalsIgnoreCase( filterConfig.getFilterDef().getAsyncSupported())) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } if( Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res, this}; SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal); } else { // 此處調(diào)用Filter的doFilter()方法 / 而 doFilter 又會調(diào)用 internalDoFilter 直到調(diào)用完所有的過濾器 filter.doFilter(request, response, this); } } catch (IOException | ServletException | RuntimeException e) { throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); throw new ServletException(sm.getString("filterChain.filter"), e); } return; } // 從最后一個開始調(diào)用 try { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(request); lastServicedResponse.set(response); } if (request.isAsyncSupported() && !servletSupportsAsync) { request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE); } // 包裝請求 if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse) && Globals.IS_SECURITY_ENABLED ) { final ServletRequest req = request; final ServletResponse res = response; Principal principal = ((HttpServletRequest) req).getUserPrincipal(); Object[] args = new Object[]{req, res}; SecurityUtil.doAsPrivilege("service", servlet, classTypeUsedInService, args, principal); } else { servlet.service(request, response); } } catch (IOException | ServletException | RuntimeException e) { throw e; } catch (Throwable e) { e = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(e); throw new ServletException(sm.getString("filterChain.servlet"), e); } finally { if (ApplicationDispatcher.WRAP_SAME_OBJECT) { lastServicedRequest.set(null); lastServicedResponse.set(null); } } }總結(jié)
職責(zé)鏈模式通過建立一條鏈來組織請求的處理者,請求將沿著鏈進(jìn)行傳遞,請求發(fā)送者無須知道請求在何時、何處以及如何被處理,實(shí)現(xiàn)了請求發(fā)送者與處理者的解耦。在軟件開發(fā)中,如果遇到有多個對象可以處理同一請求時可以應(yīng)用職責(zé)鏈模式,例如在Web應(yīng)用開發(fā)中創(chuàng)建一個過濾器(Filter)鏈來對請求數(shù)據(jù)進(jìn)行過濾,在工作流系統(tǒng)中實(shí)現(xiàn)公文的分級審批等等,使用職責(zé)鏈模式可以較好地解決此類問題。
優(yōu)點(diǎn)
降低耦合度,分離了請求與處理,無須知道是哪個對象處理其請求
簡化對象的相互連接,僅保持一個指向后者的引用,而不需保持所有候選接受者的引用
擴(kuò)展容易,新增具體請求處理者,只需要在客戶端重新建鏈即可,無需破壞原代碼
缺點(diǎn)
如果請求沒有明確的接收者,那么就不能保證它一定會被處理,該請求可能一直到鏈的末端都得不到處理;一個請求也可能因職責(zé)鏈沒有被正確配置而得不到處理
較長的職責(zé)鏈,請求的處理可能涉及到多個處理對象,系統(tǒng)性能將受到一定影響,而且在進(jìn)行代碼調(diào)試時不太方便。
如果建鏈不當(dāng),可能會造成循環(huán)調(diào)用,將導(dǎo)致系統(tǒng)陷入死循環(huán)。
金無足赤,人無完人。就像所有的設(shè)計模式一樣,有優(yōu)點(diǎn)優(yōu)缺點(diǎn),但是總的來說優(yōu)點(diǎn)必定大于缺點(diǎn)或者說缺點(diǎn)相對于優(yōu)點(diǎn)來說更可控。
說點(diǎn)什么參考文獻(xiàn):http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html
全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter11/battcn-chain-responsibility
個人QQ:1837307557
battcn開源群(適合新手):391619659
微信公眾號:battcn(歡迎調(diào)戲)
福利關(guān)注公眾號:battcn,回復(fù)springboot即可獲得
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70629.html
摘要:面向?qū)ο蟪R姷脑O(shè)計模式有策略模式模板方法觀察者模式責(zé)任鏈模式以及工廠模式,使用表達(dá)式函數(shù)式編程思維有助于避免面向?qū)ο箝_發(fā)中的那些固定代碼。 本文是一篇《Java 8實(shí)戰(zhàn)》的閱讀筆記,閱讀大約需要5分鐘。 有點(diǎn)標(biāo)題黨,但是這確實(shí)是我最近使用Lambda表達(dá)式的感受。設(shè)計模式是過去的一些好的經(jīng)驗(yàn)和套路的總結(jié),但是好的語言特性可以讓開發(fā)者不去考慮這些設(shè)計模式。面向?qū)ο蟪R姷脑O(shè)計模式有策略模式...
摘要:前言近期在做的攔截器功能,正好用到了責(zé)任鏈模式。通過官方圖就可以非常清楚的看出是一個責(zé)任鏈模式用責(zé)任鏈模式設(shè)計一個攔截器對于攔截器來說使用責(zé)任鏈模式再好不過了。設(shè)置攔截器到責(zé)任鏈中時通過反射將的值保存到各個攔截器中。 showImg(https://segmentfault.com/img/remote/1460000016756077?w=1733&h=1300); 前言 近期在做 ...
摘要:推文用設(shè)計模式解構(gòu)三國是一種什么體驗(yàn)行為型設(shè)計模式一策略模式工廠模式優(yōu)化結(jié)構(gòu)狀態(tài)模式隨著狀態(tài)改變而改變行為。推文狀態(tài)機(jī)與狀態(tài)模式責(zé)任鏈模式多個對象依次處理請求前者指定后者。代理模式代理針對一個對象,為了增加控制等中介雙方都是多個,為了解耦。 策略模式 選擇使用封裝好的一系列算法,可相互替換。 類比:商店[Context]買完衣服買單[Stratege](現(xiàn)金[Concrete Stra...
摘要:設(shè)計模式責(zé)任鏈模式顧名思義,責(zé)任鏈模式為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發(fā)送者和接收者進(jìn)行解耦。增強(qiáng)給對象指派職責(zé)的靈活性。通過改變鏈內(nèi)的成員或者調(diào)動它們的次序,允許動態(tài)地新增或者刪除責(zé)任。 設(shè)計模式 - 責(zé)任鏈模式 顧名思義,責(zé)任鏈模式(Chain of Responsibility Pattern)為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型...
摘要:迭代器模式屬于行為型模式的一種,提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內(nèi)部細(xì)節(jié)。迭代器模式把在元素之間游走的責(zé)任交給迭代器,而不是聚合對象。 迭代器模式(Iterator Pattern)屬于行為型模式的一種,提供一種方法訪問一個容器中各個元素,而又不需要暴露該對象的內(nèi)部細(xì)節(jié)。 概述 迭代器模式聽起來可能感覺很陌生,但是實(shí)際上,迭代器模式是所有設(shè)計模式中最簡單也是...
閱讀 2941·2023-04-26 01:52
閱讀 3468·2021-09-04 16:40
閱讀 3629·2021-08-31 09:41
閱讀 1764·2021-08-09 13:41
閱讀 556·2019-08-30 15:54
閱讀 2960·2019-08-30 11:22
閱讀 1612·2019-08-30 10:52
閱讀 948·2019-08-29 13:24