<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          責(zé)任鏈模式——更靈活的 if else

          共 8325字,需瀏覽 17分鐘

           ·

          2020-10-12 04:53

          責(zé)任鏈,顧名思義,就是用來處理相關(guān)事務(wù)責(zé)任的一條執(zhí)行鏈,執(zhí)行鏈上有多個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都有機(jī)會(huì)(條件匹配)處理請(qǐng)求事務(wù),如果某個(gè)節(jié)點(diǎn)處理完了就可以根據(jù)實(shí)際業(yè)務(wù)需求傳遞給下一個(gè)節(jié)點(diǎn)繼續(xù)處理或者返回處理完畢。這種模式給予請(qǐng)求的類型,對(duì)請(qǐng)求的發(fā)送者和接收者進(jìn)行解耦。屬于行為型模式。

          在這種模式中,通常每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用。如果一個(gè)對(duì)象不能處理該請(qǐng)求,那么它會(huì)把相同的請(qǐng)求傳給下一個(gè)接收者,依此類推。


          先來看一段代碼

          public?void?test(int?i,?Request?request){
          ??if(i==1){
          ????Handler1.response(request);
          ??}else?if(i?==?2){
          ????Handler2.response(request);
          ??}else?if(i?==?3){
          ????Handler3.response(request);
          ??}else?if(i?==?4){
          ????Handler4.response(request);
          ??}else{
          ????Handler5.response(request);
          ??}
          }

          代碼的業(yè)務(wù)邏輯是這樣的,方法有兩個(gè)參數(shù):整數(shù) i 和一個(gè)請(qǐng)求 request,根據(jù) i 的值來決定由誰來處理 request,如果 i==1,由 Handler1來處理,如果 i==2,由 Handler2 來處理,以此類推。在編程中,這種處理業(yè)務(wù)的方法非常常見,所有處理請(qǐng)求的類由if…else…條件判斷語句連成一條責(zé)任鏈來對(duì)請(qǐng)求進(jìn)行處理,相信大家都經(jīng)常用到。這種方法的優(yōu)點(diǎn)是非常直觀,簡單明了,并且比較容易維護(hù),但是這種方法也存在著幾個(gè)比較令人頭疼的問題:

          • 代碼臃腫:實(shí)際應(yīng)用中的判定條件通常不是這么簡單地判斷是否為1或者是否為2,也許需要復(fù)雜的計(jì)算,也許需要查詢數(shù)據(jù)庫等等,這就會(huì)有很多額外的代碼,如果判斷條件再比較多,那么這個(gè)if…else…語句基本上就沒法看了。
          • 耦合度高:如果我們想繼續(xù)添加處理請(qǐng)求的類,那么就要繼續(xù)添加if…else…判定條件;另外,這個(gè)條件判定的順序也是寫死的,如果想改變順序,那么也只能修改這個(gè)條件語句。

          既然缺點(diǎn)我們已經(jīng)清楚了,就要想辦法來解決。這個(gè)場(chǎng)景的業(yè)務(wù)邏輯很簡單:如果滿足條件1,則由 Handler1 來處理,不滿足則向下傳遞;如果滿足條件2,則由 Handler2 來處理,不滿足則繼續(xù)向下傳遞,以此類推,直到條件結(jié)束。其實(shí)改進(jìn)的方法也很簡單,就是把判定條件的部分放到處理類中,這就是責(zé)任連模式的原理。


          定義

          責(zé)任鏈模式(Chain of Responsibility Pattern):使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免了請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有對(duì)象處理它為止。


          角色

          • Handler:抽象處理類,抽象處理類中主要包含一個(gè)指向下一處理類的成員變量nextHandler和一個(gè)處理請(qǐng)求的方法handRequest,handRequest方法的主要主要思想是,如果滿足處理的條件,則有本處理類來進(jìn)行處理,否則由nextHandler來處理
          • ConcreteHandler:具體處理類主要是對(duì)具體的處理邏輯和處理的適用條件進(jìn)行實(shí)現(xiàn)。具體處理者接到請(qǐng)求后,可以選擇將請(qǐng)求處理掉,或者將請(qǐng)求傳給下家。由于具體處理者持有對(duì)下家的引用,因此,如果需要,具體處理者可以訪問下家
          • Client:客戶端

          類圖

          coding

          public?abstract?class?Handler?{
          ????private?Handler?nextHandler;
          ????private?int?level;

          ????public?Handler(int?level)?{
          ????????this.level?=?level;
          ????}

          ????public?void?setNextHandler(Handler?handler){
          ????????this.nextHandler?=?handler;
          ????}

          ????public?final?void?handlerRequest(Request?request){
          ????????if(level?==?request.getLevel()){
          ????????????this.response(request);
          ????????}else{
          ????????????if?(this.nextHandler?!=?null){
          ????????????????this.nextHandler.handlerRequest(request);
          ????????????}else{
          ????????????????System.out.println("===已經(jīng)沒有處理器了===");
          ????????????}
          ????????}

          ????}
          ????//?抽象方法,子類實(shí)現(xiàn)
          ????public?abstract?void?response(Request?request);
          }

          class?Request?{
          ????int?level?=?0;
          ????public?Request(int?level){
          ????????this.level?=?level;
          ????}
          ????public?int?getLevel()?{
          ????????return?level;
          ????}
          }
          public?class?ConcreteHandler1?extends?Handler?{
          ????public?ConcreteHandler1(int?level)?{
          ????????super(level);
          ????}

          ????@Override
          ????public?void?response(Request?request)?{
          ????????System.out.println("請(qǐng)求由處理器1進(jìn)行處理");
          ????}
          }

          public?class?ConcreteHandler2?extends?Handler?{
          ?//...
          }

          public?class?ConcreteHandler2?extends?Handler?{
          ?//...
          }
          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????ConcreteHandler1?handler1?=?new?ConcreteHandler1(1);
          ????????ConcreteHandler2?handler2?=?new?ConcreteHandler2(2);
          ????????ConcreteHandler3?handler3?=?new?ConcreteHandler3(3);
          ????//處理者構(gòu)成一個(gè)環(huán)形
          ????????handler1.setNextHandler(handler2);
          ????????handler2.setNextHandler(handler3);

          ????????handler1.handlerRequest(new?Request(1));
          ????}
          }

          實(shí)例

          當(dāng)你想要讓一個(gè)以上的對(duì)象有機(jī)會(huì)能夠處理某個(gè)請(qǐng)求的時(shí)候,就是用責(zé)任鏈模式。

          通過責(zé)任鏈模式,你可以為某個(gè)請(qǐng)求創(chuàng)建一個(gè)對(duì)象鏈。每個(gè)對(duì)象依序檢查此請(qǐng)求,并對(duì)其進(jìn)行處理,或者將它傳給鏈中的下一個(gè)對(duì)象。

          比如

          應(yīng)用

          JAVA 中的異常處理機(jī)制、JAVA WEB 中 Apache Tomcat 對(duì) Encoding 的處理,Struts2 的攔截器,JSP、Servlet 的 Filter 均是責(zé)任鏈的典型應(yīng)用。

          Servlet 中的責(zé)任鏈

          public?final?class?ApplicationFilterChain?implements?FilterChain?{
          ????private?static?final?ThreadLocal?lastServicedRequest;
          ????private?static?final?ThreadLocal?lastServicedResponse;
          ????public?static?final?int?INCREMENT?=?10;
          ????private?ApplicationFilterConfig[]?filters?=?new?ApplicationFilterConfig[0];
          ????private?int?pos?=?0;??//下一個(gè)要執(zhí)行的filter的位置
          ????private?int?n?=?0;????//filter個(gè)數(shù)
          ????private?Servlet?servlet?=?null;
          ????public?ApplicationFilterChain()?{
          ????}

          ????public?void?doFilter(ServletRequest?request,?ServletResponse?response)?throws?IOException,?ServletException?{
          ????????if?(Globals.IS_SECURITY_ENABLED)?{
          ????????????final?ServletRequest?req?=?request;
          ????????????final?ServletResponse?res?=?response;

          ????????????try?{
          ????????????????AccessController.doPrivileged(new?PrivilegedExceptionAction()?{
          ????????????????????public?Void?run()?throws?ServletException,?IOException?{
          ????????????????????????ApplicationFilterChain.this.internalDoFilter(req,?res);
          ????????????????????????return?null;
          ????????????????????}
          ????????????????});
          ????????????}?catch?(PrivilegedActionException?var7)?{
          ????????????????Exception?e?=?var7.getException();
          ????????????????if?(e?instanceof?ServletException)?{
          ????????????????????throw?(ServletException)e;
          ????????????????}

          ????????????????if?(e?instanceof?IOException)?{
          ????????????????????throw?(IOException)e;
          ????????????????}

          ????????????????if?(e?instanceof?RuntimeException)?{
          ????????????????????throw?(RuntimeException)e;
          ????????????????}

          ????????????????throw?new?ServletException(e.getMessage(),?e);
          ????????????}
          ????????}?else?{
          ????????????this.internalDoFilter(request,?response);
          ????????}
          ????}

          FilterChain 就是一條過濾鏈。其中每個(gè)過濾器(Filter)都可以決定是否執(zhí)行下一步。過濾分兩個(gè)方向,進(jìn)和出:

          進(jìn):在把ServletRequest和ServletResponse交給Servlet的service方法之前,需要進(jìn)行過濾

          出:在service方法完成后,往客戶端發(fā)送之前,需要進(jìn)行過濾

          Spring MVC 中的責(zé)任鏈

          Spring MVC 的 diapatcherServlet 的 doDispatch 方法中,獲取與請(qǐng)求匹配的處理器 HandlerExecutionChain就是用到了責(zé)任鏈模式。

          protected?void?doDispatch(HttpServletRequest?request,?HttpServletResponse?response)?throws?Exception?{
          ????????HttpServletRequest?processedRequest?=?request;
          ????????HandlerExecutionChain?mappedHandler?=?null;????//使用到了責(zé)任鏈模式
          ????????boolean?multipartRequestParsed?=?false;
          ????????WebAsyncManager?asyncManager?=?WebAsyncUtils.getAsyncManager(request);

          ????????try?{
          ????????????try?{
          ????????????????ModelAndView?mv?=?null;
          ????????????????Object?dispatchException?=?null;

          ????????????????try?{
          ????????????????????processedRequest?=?this.checkMultipart(request);
          ????????????????????multipartRequestParsed?=?processedRequest?!=?request;
          ????????????????????mappedHandler?=?this.getHandler(processedRequest);?
          ????????????????????if?(mappedHandler?==?null)?{
          ????????????????????????this.noHandlerFound(processedRequest,?response);
          ????????????????????????return;
          ????????????????????}

          ????????????????????HandlerAdapter?ha?=?this.getHandlerAdapter(mappedHandler.getHandler());
          ????????????????????String?method?=?request.getMethod();
          ????????????????????boolean?isGet?=?"GET".equals(method);
          ????????????????????if?(isGet?||?"HEAD".equals(method))?{
          ????????????????????????long?lastModified?=?ha.getLastModified(request,?mappedHandler.getHandler());
          ????????????????????????if?((new?ServletWebRequest(request,?response)).checkNotModified(lastModified)?&&?isGet)?{
          ????????????????????????????return;
          ????????????????????????}
          ????????????????????}
          ??????????//責(zé)任鏈模式執(zhí)行預(yù)處理方法,其實(shí)是將請(qǐng)求交給注冊(cè)的攔截器執(zhí)行
          ????????????????????if?(!mappedHandler.applyPreHandle(processedRequest,?response))?{
          ????????????????????????return;
          ????????????????????}

          ????????????????????mv?=?ha.handle(processedRequest,?response,?mappedHandler.getHandler());
          ????????????????????if?(asyncManager.isConcurrentHandlingStarted())?{
          ????????????????????????return;
          ????????????????????}

          ????????????????????this.applyDefaultViewName(processedRequest,?mv);
          ???????????????????//責(zé)任鏈執(zhí)行后處理方法
          ????????????????????mappedHandler.applyPostHandle(processedRequest,?response,?mv);
          ????????????????}?catch?(Exception?var22)?{
          ?????????????//...
          ????????}?finally?{
          ?????}
          ?}
          • SpringMVC 請(qǐng)求的流程中,執(zhí)行了攔截器相關(guān)方法 interceptor.preHandler 等等
          • 在處理 SpringMVC 請(qǐng)求時(shí),使用到職責(zé)鏈模式還使用到適配器模式
          • HandlerExecutionChain 主要負(fù)責(zé)的是請(qǐng)求攔截器的執(zhí)行和請(qǐng)求處理,但是他本身不處理請(qǐng)求,只是將請(qǐng)求分配給鏈上注冊(cè)處理器執(zhí)行,這是職責(zé)鏈實(shí)現(xiàn)方式,減少職責(zé)鏈本身與處理邏輯之間的耦合,規(guī)范了處理流程
          • HandlerExecutionChain 維護(hù)了 HandlerInterceptor 的集合, 可以向其中注冊(cè)相應(yīng)的攔截器

          總結(jié)

          責(zé)任鏈模式其實(shí)就是一個(gè)靈活版的 if…else…語句,它就是將這些判定條件的語句放到了各個(gè)處理類中,這樣做的優(yōu)點(diǎn)是比較靈活了,但同樣也帶來了風(fēng)險(xiǎn),比如設(shè)置處理類前后關(guān)系時(shí),一定要特別仔細(xì),搞對(duì)處理類前后邏輯的條件判斷關(guān)系,并且注意不要在鏈中出現(xiàn)循環(huán)引用的問題。

          優(yōu)點(diǎn)

          • 降低耦合度:將請(qǐng)求和處理分開,實(shí)現(xiàn)解耦,提高了系統(tǒng)的靈活性。
          • 簡化了對(duì)象:對(duì)象不需要知道鏈的結(jié)構(gòu)
          • 良好的擴(kuò)展性:增加處理者的實(shí)現(xiàn)很簡單,只需重寫處理請(qǐng)求業(yè)務(wù)邏輯的方法。

          缺點(diǎn)

          • 從鏈頭發(fā)出,直到有處理者響應(yīng),在責(zé)任鏈比較長的時(shí)候會(huì)影響系統(tǒng)性能,一般需要在 Handler 中設(shè)置一個(gè)最大節(jié)點(diǎn)數(shù)。
          • 請(qǐng)求遞歸,調(diào)試排錯(cuò)比較麻煩。

          使用場(chǎng)景

          • 有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求,具體哪個(gè)對(duì)象處理該請(qǐng)求由運(yùn)行時(shí)刻自動(dòng)確定。
          • 在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求。
          • 可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求。

          模式的擴(kuò)展

          職責(zé)鏈模式存在以下兩種情況。

          1. 純的職責(zé)鏈模式:一個(gè)請(qǐng)求必須被某一個(gè)處理者對(duì)象所接收,且一個(gè)具體處理者對(duì)某個(gè)請(qǐng)求的處理只能采用以下兩種行為之一:自己處理(承擔(dān)責(zé)任);把責(zé)任推給下家處理。
          2. 不純的職責(zé)鏈模式:允許出現(xiàn)某一個(gè)具體處理者對(duì)象在承擔(dān)了請(qǐng)求的一部分責(zé)任后又將剩余的責(zé)任傳給下家的情況,且一個(gè)請(qǐng)求可以最終不被任何接收端對(duì)象所接收。

          參考

          《研磨設(shè)計(jì)模式》
          https://wiki.jikexueyuan.com/project/java-design-pattern/chain-responsibility-pattern.html
          https://refactoringguru.cn/design-patterns/chain-of-responsibility

          瀏覽 52
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产精品在线观看成人视频 | 中文字幕视频在线 | 五月丁香在线 | 天天做天天爽 | 2021国产精彩在线视频 |