1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        責(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…條件判斷語(yǔ)句連成一條責(zé)任鏈來對(duì)請(qǐng)求進(jìn)行處理,相信大家都經(jīng)常用到。這種方法的優(yōu)點(diǎn)是非常直觀,簡(jiǎn)單明了,并且比較容易維護(hù),但是這種方法也存在著幾個(gè)比較令人頭疼的問題:

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

        既然缺點(diǎn)我們已經(jīng)清楚了,就要想辦法來解決。這個(gè)場(chǎng)景的業(yè)務(wù)邏輯很簡(jiǎn)單:如果滿足條件1,則由 Handler1 來處理,不滿足則向下傳遞;如果滿足條件2,則由 Handler2 來處理,不滿足則繼續(xù)向下傳遞,以此類推,直到條件結(jié)束。其實(shí)改進(jìn)的方法也很簡(jiǎ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…語(yǔ)句,它就是將這些判定條件的語(yǔ)句放到了各個(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)的靈活性。
        • 簡(jiǎn)化了對(duì)象:對(duì)象不需要知道鏈的結(jié)構(gòu)
        • 良好的擴(kuò)展性:增加處理者的實(shí)現(xiàn)很簡(jiǎn)單,只需重寫處理請(qǐng)求業(yè)務(wù)邏輯的方法。

        缺點(diǎn)

        • 從鏈頭發(fā)出,直到有處理者響應(yīng),在責(zé)任鏈比較長(zhǎng)的時(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)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品片www48888 | 免费亚洲婷婷 | 午夜成人国产精品 | 女人av网| 免费的黄色操无毛逼 | 91TS国产人妖系列 | 亚洲欧洲小说图片在线免费观看 | 操大逼的 | 在线观看黄国产 | 怡红院av在线 |