国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一文帶你讀懂設(shè)計模式之責(zé)任鏈模式

這篇具有很好參考價值的文章主要介紹了一文帶你讀懂設(shè)計模式之責(zé)任鏈模式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1.前言

emm,翻了一下之前剛?cè)肼殨r候的學(xué)習(xí)筆記,發(fā)現(xiàn)之前在熟悉業(yè)務(wù)代碼的時候曾經(jīng)專門學(xué)習(xí)并整理過過設(shè)計模式中的責(zé)任鏈模式,之前只是對其簡單了解過常用的設(shè)計模式有哪些,并未結(jié)合實例和源碼深入對其探究,利用熟悉代碼契機進行系統(tǒng)學(xué)習(xí)并整理文檔如下。

2.什么是責(zé)任鏈模式?

俗話說沒有規(guī)矩不成方圓,我們無論在工作還是生活中很多事情都需要按照規(guī)定的流程辦事,這樣的流程往往都是環(huán)環(huán)相扣的,上一部完成之后才會流轉(zhuǎn)到下一步執(zhí)行。比如我們在做飯時都是先買菜、洗菜、切菜、炒菜、裝盤在這樣的過程中只有上一步完成之后才能開始下一步最后得到一道做好的菜;又比如在晉升提名時,首先我們要做一個述職報告進行述職,然后就是評審小組打分,評審小組篩選通過后,流轉(zhuǎn)到項目組領(lǐng)導(dǎo)處審批,項目組領(lǐng)導(dǎo)根據(jù)述職報告和評審小組分?jǐn)?shù)決定是否晉升,項目組領(lǐng)導(dǎo)同意之后最后流轉(zhuǎn)到部門領(lǐng)導(dǎo)審批并給出最后結(jié)果。像這種一步一步完成流程都可以通過責(zé)任鏈模式來實現(xiàn)。

  • 簡介: 責(zé)任鏈模式顧名思義是將不同職責(zé)的步驟串聯(lián)起來執(zhí)行,并且一個步驟執(zhí)行完成之后才能夠執(zhí)行下一個步驟。從名字可以看出通常責(zé)任鏈模式使用鏈表來完成。因此當(dāng)執(zhí)行任務(wù)的請求發(fā)起時,從責(zé)任鏈上第一步開始往下傳遞,直到最后一個步驟完成。在責(zé)任鏈模式當(dāng)中,客戶端只用執(zhí)行一次流程開始的請求便不再需要參與到流程執(zhí)行當(dāng)中,責(zé)任鏈上的流程便能夠自己一直往下執(zhí)行,客戶端同樣也并不關(guān)心執(zhí)行流程細節(jié),從而實現(xiàn)與流程之間的解耦。
  • 模式結(jié)構(gòu):責(zé)任鏈模式主要角色如下:

?抽象處理器(Handler):處理器抽象接口,定義了處理請求的方法和執(zhí)行下一步處理的處理器。

?具體處理器(ConcreteHandler):執(zhí)行請求的具體實現(xiàn),先根據(jù)請求執(zhí)行處理邏輯,完成之后將請求交給下一個處理器執(zhí)行。

?調(diào)用者:調(diào)用者通過創(chuàng)建處理器并將請求交給處理器進行處理。

  • 相關(guān)代碼:
// 抽象處理器
public abstract class Handler {
    private Handler next;

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }
    public abstract void handle(Object request);
}

// 具體處理器 1
public class ConcreteHandler1 extends Handler {
    @Override
    public void handle(Object request) {
        System.out.println("concrete handler 1 execute request. request: " + request);
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}

// 具體處理器 2
public class ConcreteHandler2 extends Handler {
    @Override
    public void handle(Object request) {
        System.out.println("concrete handler 2 execute request. request: " + request);
        if (getNext() != null){
            getNext().handle(request);
        }
    }
}

// 具體處理器 3
public class ConcreteHandler3 extends Handler {
    @Override
    public void handle(Object request) {
        System.out.println("concrete handler 3 execute request. request: " + request);
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}


public static void main(String[] args) {
    Handler concreteHandler1 = new ConcreteHandler1();
    Handler concreteHandler2 = new ConcreteHandler2();
    Handler concreteHandler3 = new ConcreteHandler3();

    concreteHandler1.setNext(concreteHandler2);
    concreteHandler2.setNext(concreteHandler3);

    concreteHandler1.handle("my request.");
}



從上面的代碼我們可以看到其實責(zé)任鏈模式是非常簡單的,但是其中有幾個點需要注意一下:

  • 首先我們需要對整個責(zé)任鏈進行初始化,即設(shè)置每個處理器的 next。
  • 在每個具體處理器處理完之后需要手動調(diào)用下一個處理器的 handle 方法來執(zhí)行下一步處理,這里其實還可以使用模板方法模式進行優(yōu)化。

控制臺輸出如下:

concrete handler 1 execute request. request: my request.
concrete handler 2 execute request. request: my request.
concrete handler 3 execute request. request: my request.



3.具體實例demo

日常請假為例。請假申請會先到你的直屬 leader 處審批,審批通過后再到部門 leader 處審批,部門 leader 通過后,最后到人事處報備記錄請假天數(shù)。如果在傳統(tǒng)企業(yè)里面,我們需要手寫一份請假表,然后跑到直屬 leader 辦公室,讓直屬 leader 簽字,然后再到部門 leader 辦公室簽字,最后還要跑到人事處上交請假單,這樣相當(dāng)于發(fā)出了三次請求,才能走完整個請假流程。

但是在現(xiàn)代各種 OA 系統(tǒng)管理下,整個請假流程就變的簡單了,我們只需要發(fā)起一次請假請求,接下來你的請假請求便會自動的在審批人中間進行流轉(zhuǎn),這個時候我們的責(zé)任鏈模式便派上用場。代碼如下:

// 請假抽象處理器
public abstract class DayOffHandler {
    private DayOffHandler next;

    public DayOffHandler getNext() {
        return next;
    }

    public void setNext(DayOffHandler next) {
        this.next = next;
    }
    public abstract void handle(String request);

}
// 直屬 leader 處理
public class GroupLeaderHandler extends DayOffHandler {
    @Override
    public void handle(String request) {
        System.out.println("直屬 leader 審查: " + request);
        System.out.println("同意請求");
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}
// 部門 leader 處理
public class DepartmentLeaderHandler extends DayOffHandler{
    @Override
    public void handle(String request) {
        System.out.println("部門 leader 審查: " + request);
        System.out.println("同意請求");
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}
// 人事處處理
public class HRHandler extends DayOffHandler {
    @Override
    public void handle(String request) {
        System.out.println("人事處審查: " + request);
        System.out.println("同意請求,記錄請假");
        if (getNext() != null) {
            getNext().handle(request);
        }
    }
}




上面的代碼定義了請假抽象處理類和三個具體的處理人,我們需要將這三個處理人的流程初始化串聯(lián)起來,并且一步步的執(zhí)行下去,像下面這張圖所示流程一樣,于是客戶端的代碼如下:

public static void main(String[] args) {

    DayOffHandler groupLeaderHandler = new GroupLeaderHandler();
    DayOffHandler departmentLeaderHandler = new DepartmentLeaderHandler();
    DayOffHandler hrHandler = new HRHandler();
    groupLeaderHandler.setNext(departmentLeaderHandler);
    departmentLeaderHandler.setNext(hrHandler);

    System.out.println("收到面試通知,需要請假");
    String request = "家中有事,請假半天,望批準(zhǔn)";
    System.out.println("發(fā)起請求:");
    groupLeaderHandler.handle(request);
}



客戶端代碼中可以看到,我們首先實例化了三個具體處理人,然后通過 setNext 方法將他們串聯(lián)起來,而我們只需向直屬 leader 發(fā)起一次請假請求即可,整個審批流程便能夠自動的執(zhí)行下去,不需要再挨個跑辦公室申請了。執(zhí)行后的結(jié)果如下:

收到面試通知,需要請假
發(fā)起請求:
直屬 leader 審查: 家中有事,請假半天,望批準(zhǔn)
同意請求
部門 leader 審查: 家中有事,請假半天,望批準(zhǔn)
同意請求
人事處審查: 家中有事,請假半天,望批準(zhǔn)
同意請求,記錄請假



4.責(zé)任鏈模式在源碼中的應(yīng)用

說到責(zé)任鏈模式,那么最著名的當(dāng)然是 Servlet 中的過濾器 Filter 了,在這攔截器和過濾器的體系中都使用責(zé)任鏈模式來依次處理每個請求,首先看看過濾器 Filter 的使用方式。Filter 接口如下:

public interface Filter {
    default void init(FilterConfig filterConfig) throws ServletException {
    }

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    default void destroy() {
    }
}


  • FilterChain 便是過濾器 Filter 的一條責(zé)任鏈,其代碼如下:
public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}


public final class ApplicationFilterChain implements FilterChain {
    
    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<Void>() {
                    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);
        }

    }

    private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.pos < this.n) {
            ApplicationFilterConfig filterConfig = this.filters[this.pos++];

            try {
                Filter filter = filterConfig.getFilter();
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
                }

                if (Globals.IS_SECURITY_ENABLED) {
                    Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                    Object[] args = new Object[]{request, response, this};
                    SecurityUtil.doAsPrivilege("doFilter", filter, classType, args, principal);
                } else {
                    filter.doFilter(request, response, this);
                }

            } catch (ServletException | RuntimeException | IOException var15) {
                throw var15;
            } catch (Throwable var16) {
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.filter"), e);
            }
        } else {
            try {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set(request);
                    lastServicedResponse.set(response);
                }

                if (request.isAsyncSupported() && !this.servletSupportsAsync) {
                    request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", Boolean.FALSE);
                }

                if (request instanceof HttpServletRequest && response instanceof HttpServletResponse && Globals.IS_SECURITY_ENABLED) {
                    Principal principal = ((HttpServletRequest)request).getUserPrincipal();
                    Object[] args = new Object[]{request, response};
                    SecurityUtil.doAsPrivilege("service", this.servlet, classTypeUsedInService, args, principal);
                } else {
                    this.servlet.service(request, response);
                }
            } catch (ServletException | RuntimeException | IOException var17) {
                throw var17;
            } catch (Throwable var18) {
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var18);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
                if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                    lastServicedRequest.set((Object)null);
                    lastServicedResponse.set((Object)null);
                }

            }

        }
    }
}



  • internalDoFilter() 方法中,可以看到整個 FilterChain 上使用數(shù)組 filters 存放每一個過濾器及其配置并使用 pos 記錄當(dāng)前遍歷到哪一個過濾器,然后再執(zhí)行獲取到的 FilterdoFilter 方法。與前面所講鏈表方式存放不同,這里的鏈路使用數(shù)組來進行存放。

  • spring中的責(zé)任鏈模式

SpringMVC 中的 Interceptor 同樣也用到了責(zé)任鏈模式。首先來看看 Interceptor 的抽象處理類;

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}




在抽象處理類中,定義了三個方法,分別是處理前置處理器、后置處理器和整個流程完成之后的處理。通過 HandlerExecutionChain 將攔截器串聯(lián)起來,在 HandlerExecutionChain 中,我們需要關(guān)注 applyPreHandle、applyPostHandletriggerAfterCompletion 三個方法,這三個方法分別執(zhí)行了攔截器中所定義的 preHandle 、postHandleafterCompletion 方法。并且從代碼中也能夠看處,和前面的過濾器一樣,所有的攔截器都存放在 interceptors 數(shù)組中,并在三個方法中遍歷 interceptors 數(shù)組依次執(zhí)行相應(yīng)的方法

public class HandlerExecutionChain {
    @Nullable
    private HandlerInterceptor[] interceptors;

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }

        return true;
    }

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for(int i = interceptors.length - 1; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }

    }

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for(int i = this.interceptorIndex; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];

                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                } catch (Throwable var8) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                }
            }
        }

    }
}



5.總結(jié)

責(zé)任鏈模式也是常見的設(shè)計模式,各個不同職責(zé)的處理器串聯(lián)起來,通過一次請求便能夠執(zhí)行完每個處理器的處理方法。通過這樣的方式請求的發(fā)送者只需發(fā)出一次請求同時也不需要知道詳細的鏈路結(jié)構(gòu);而請求的接送方只關(guān)心自己的處理邏輯,自己處理完成之后將請求傳遞給下一個接收者,從而完成自己的任務(wù),這樣便實現(xiàn)了請求發(fā)送者和接收者的解耦。而從源碼分析中可以看到,責(zé)任鏈模式雖然常見使用鏈表結(jié)構(gòu),但是使用數(shù)組和列表同樣能夠完成需求。

作者:京東科技 宋慧超

來源:京東云開發(fā)者社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-655653.html

到了這里,關(guān)于一文帶你讀懂設(shè)計模式之責(zé)任鏈模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 抖音小店無貨源處罰全解,一文帶你讀懂官方規(guī)則,合理規(guī)避風(fēng)險

    抖音小店無貨源處罰全解,一文帶你讀懂官方規(guī)則,合理規(guī)避風(fēng)險

    大家好,我是電商年年 根據(jù)官方解釋, “無貨源店鋪” ,指店鋪經(jīng)營者沒有現(xiàn)貨,在網(wǎng)上找產(chǎn)品找貨源,在未取得貨源方授權(quán)的情況下,把貨源信息“搬運”到自己的店鋪中,等有消費者下單,店鋪經(jīng)營者再去 貨源方店鋪下 單,由貨源方向消費者派單發(fā)貨。 ? 那官方對于

    2024年02月03日
    瀏覽(22)
  • 一口氣帶你讀懂跨境電商出海模式

    作為一名跨境電商賣家,掌握正確的“出海模式”至關(guān)重要。今天,就讓我們一起揭開跨境電商的神秘面紗,探索它的各種出海模式,為你的電商之旅提供指引。 1???國際站模式 ?起步門檻:10W及以內(nèi) ?利潤:高 ?客單價:較高(以?B2B?大單為主) ?運營難度:中低,

    2024年02月21日
    瀏覽(27)
  • Linux - 一篇帶你讀懂 Curl Proxy 代理模式

    Linux - 一篇帶你讀懂 Curl Proxy 代理模式

    curl 是一個很有名的處理網(wǎng)絡(luò)請求的 類Unix 工具。出于某種原因,我們進行網(wǎng)絡(luò)請求,需要設(shè)置代理。本文講全面介紹如何為 curl 設(shè)置代理 設(shè)置代理參數(shù) 基本用法 設(shè)置 HTTP 代理 下面兩種設(shè)置代理的方式是可以的 由于代理地址的默認協(xié)議為? HTTP, 所以可以省略,按照下面的

    2024年02月05日
    瀏覽(29)
  • 一文帶你通俗理解23種軟件設(shè)計模式(推薦收藏,適合小白學(xué)習(xí),附帶C++例程完整源碼)

    一文帶你通俗理解23種軟件設(shè)計模式(推薦收藏,適合小白學(xué)習(xí),附帶C++例程完整源碼)

    作者:翟天保Steven 版權(quán)聲明:著作權(quán)歸作者所有,商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處 ? ? ? ?設(shè)計模式是為了解決在軟件開發(fā)過程中遇到的某些問題而形成的思想。同一場景有多種設(shè)計模式可以應(yīng)用,不同的模式有各自的優(yōu)缺點,開發(fā)者可以基于自身需求

    2024年02月09日
    瀏覽(90)
  • 《設(shè)計模式》責(zé)任鏈模式

    《設(shè)計模式》責(zé)任鏈模式

    定義 : 責(zé)任鏈模式將鏈中每一個節(jié)點都看成一個對象,并且將這些節(jié)點對象連成一條鏈,請求會沿著這條鏈進行傳遞,直到有對象處理它為止,這使得多個對象都有機會接收請求,避免了請求發(fā)送者和接收者之間的耦合。 屬于 行為型 設(shè)計模式。 責(zé)任鏈模式的角色組成 :

    2024年02月13日
    瀏覽(17)
  • 設(shè)計模式:責(zé)任鏈模式

    責(zé)任鏈模式(Chain of Responsibility Pattern)是一種行為型設(shè)計模式,它允許多個對象按照順序處理請求,直到其中一個對象能夠處理該請求為止。責(zé)任鏈模式將請求發(fā)送者和接收者解耦,使得多個對象都有機會處理請求,同時避免了請求發(fā)送者與接收者之間的直接耦合關(guān)系。 在

    2024年02月07日
    瀏覽(21)
  • 【設(shè)計模式】責(zé)任鏈模式

    【設(shè)計模式】責(zé)任鏈模式

    顧名思義,責(zé)任鏈模式(Chain of Responsibility Pattern)為請求創(chuàng)建了一個接收者對象的鏈。這種模式給予請求的類型,對請求的發(fā)送者和接收者進行解耦。這種類型的設(shè)計模式屬于行為型模式。 在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處

    2024年02月12日
    瀏覽(20)
  • 設(shè)計模式-責(zé)任鏈模式

    遇到一個面試的場景題目,讓實現(xiàn)稅率的計算 請使用Java語言實現(xiàn)如下稅率計算: 1~5000 稅率 0 5001~8000 3% 8001~17000 10% 17001~30000 20% 30001~40000 25% 40001~60000 30% 60001~85000 35% 85001~ 45% 要求 ⅰ. 邏輯正確,代碼優(yōu)雅 ⅱ. 可擴展性,考慮區(qū)間的變化,比如說起征點從5000變成10000等等,或者

    2024年02月11日
    瀏覽(23)
  • 設(shè)計模式—責(zé)任鏈模式

    設(shè)計模式—責(zé)任鏈模式

    一、待解決問題 : 減少代碼中 if else 語句,降低代碼圈復(fù)雜度或深度,增強可讀性。 1、需求背景: 采購訂單創(chuàng)建,需要驗證采購員、物料、供應(yīng)商、供應(yīng)商的銀行賬號等信息。如采購員權(quán)限到期、或供應(yīng)商失效等問題,都無法下單。 2、代碼如下: 學(xué)習(xí)使用責(zé)任鏈模式后

    2024年02月10日
    瀏覽(19)
  • 設(shè)計模式——責(zé)任鏈模式

    設(shè)計模式——責(zé)任鏈模式

    使多個對象都有機會處理請求,從而避免了請求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,知道有對象處理它為止。 優(yōu)點 能將請求和處理分開。請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌,兩者解耦提高系

    2024年02月15日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包