亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java設(shè)計(jì)模式之責(zé)任鏈模式

 更新時(shí)間:2022年10月11日 09:09:09   作者:tianClassmate  
這篇文章介紹了Java設(shè)計(jì)模式之責(zé)任鏈模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

本文通過(guò)圖書(shū)館管理系統(tǒng)中,用戶名校驗(yàn)、密碼校驗(yàn)、需要增加問(wèn)題,每次都要增加if判斷語(yǔ)句,將其改用責(zé)任鏈模式進(jìn)行鏈?zhǔn)秸{(diào)用,為了讓代碼更加的優(yōu)雅,我們使用之前學(xué)過(guò)的建造者模式就代碼進(jìn)行改造。接著我們會(huì)介紹責(zé)任鏈模式在我們常用的框架中的運(yùn)用,最后是責(zé)任鏈模式的優(yōu)缺點(diǎn)和應(yīng)用場(chǎng)景。

讀者可以拉取完整代碼到本地進(jìn)行學(xué)習(xí),實(shí)現(xiàn)代碼均測(cè)試通過(guò)后上傳到碼云本地源碼下載。

一、引出問(wèn)題

小王給老王打造了一套圖書(shū)館管理系統(tǒng),隨著訪問(wèn)量的不斷增加,老王要求增加訪問(wèn)的用戶名校驗(yàn)。

小王說(shuō)這有何難,說(shuō)著就在用戶訪問(wèn)圖書(shū)館之前加了一層判斷語(yǔ)句,判斷用戶名是否合法。過(guò)了一段時(shí)間后,又給每個(gè)用戶頒發(fā)了一個(gè)密碼,就需要在用戶名校驗(yàn)通過(guò)以后校驗(yàn)密碼。

小王就準(zhǔn)備在用戶名的判斷語(yǔ)句后,增加密碼的校驗(yàn)語(yǔ)句。老王趕忙攔住了要繼續(xù)更改代碼的小王。如果以后再增加角色校驗(yàn)、權(quán)限校驗(yàn)、你準(zhǔn)備寫(xiě)多少個(gè)判斷語(yǔ)句。

而且你把軟件設(shè)計(jì)原則中的——開(kāi)閉原則丟到哪里去了。

你可以考慮使用一種模式,將所有的校驗(yàn)方法都獨(dú)立出來(lái)一個(gè)類,每一個(gè)類只負(fù)責(zé)處理各自的校驗(yàn)邏輯,當(dāng)前的校驗(yàn)類通過(guò)以后傳遞給下一個(gè)校驗(yàn)類進(jìn)行處理,這樣每次增加新的邏輯判斷都只需要增加校驗(yàn)類就行了。

就像是一條流水線,每個(gè)類負(fù)責(zé)處理線上的一個(gè)環(huán)節(jié)。

二、責(zé)任鏈模式的概念和使用

實(shí)際上,老王提出來(lái)的正是行為型設(shè)計(jì)模式中的——**責(zé)任鏈模式。

責(zé)任鏈模式正如它的名字一樣,將每個(gè)職責(zé)的步驟串聯(lián)起來(lái)執(zhí)行,并且一個(gè)步驟執(zhí)行完成之后才能夠執(zhí)行下一個(gè)步驟。

從名字可以看出通常責(zé)任鏈模式使用鏈表來(lái)完成。 因此當(dāng)執(zhí)行任務(wù)的請(qǐng)求發(fā)起時(shí),從責(zé)任鏈上第一步開(kāi)始往下傳遞,直到最后一個(gè)步驟完成。

在責(zé)任鏈模式當(dāng)中, 客戶端只用執(zhí)行一次流程開(kāi)始的請(qǐng)求便不再需要參與到流程執(zhí)行當(dāng)中,責(zé)任鏈上的流程便能夠自己一直往下執(zhí)行,

客戶端同樣也并不關(guān)心執(zhí)行流程細(xì)節(jié),從而實(shí)現(xiàn)與流程之間的解耦。

責(zé)任鏈模式需要有兩個(gè)角色:

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

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

基于責(zé)任鏈模式實(shí)現(xiàn)圖書(shū)館的用戶名校驗(yàn)和密碼校驗(yàn)。

抽象處理器:

/**
 * @author tcy
 * @Date 22-08-2022
 */
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);


}

用戶名校驗(yàn)處理器:

/**
 * @author tcy
 * @Date 23-08-2022
 */
public class ConcreteHandlerUsername extends Handler{
    @Override
    public void handle(Object request) {

        //相應(yīng)的業(yè)務(wù)邏輯...
        System.out.println("用戶名校驗(yàn)通過(guò). 參數(shù): " + request);

        //調(diào)用鏈路中下一個(gè)節(jié)點(diǎn)的處理方法
        if (getNext() != null) {

            getNext().handle(request);
        }

    }
}

密碼校驗(yàn)器:

/**
 * @author tcy
 * @Date 23-08-2022
 */
public class ConcreteHandlerPassword extends Handler{
    @Override
    public void handle(Object request) {

        //相應(yīng)的業(yè)務(wù)邏輯...

        System.out.println("密碼校驗(yàn)通過(guò). 參數(shù): " + request);

        //調(diào)用鏈路中下一個(gè)節(jié)點(diǎn)的處理方法
        if (getNext() != null){

            getNext().handle(request);
        }

    }
}

客戶端調(diào)用:

public class Client {

    //普通模式----------
    public static void main(String[] args) {
        Handler concreteHandler1 = new ConcreteHandlerUsername();
        Handler concreteHandler2 = new ConcreteHandlerPassword();
    
       concreteHandler1.setNext(concreteHandler2);
    
       concreteHandler1.handle("用戶名tcy");
    
    }
}

  用戶名校驗(yàn)通過(guò). 參數(shù): 用戶名tcy
  密碼校驗(yàn)通過(guò). 參數(shù): 用戶名tcy

這樣我們就實(shí)現(xiàn)了責(zé)任鏈模式,但是這種方式我們注意到,調(diào)用方調(diào)用的時(shí)候手動(dòng)將兩個(gè)處理器set到一起,如果這條鏈路很長(zhǎng)的時(shí)候,這樣的代碼實(shí)在是太不優(yōu)雅了。

將我們?cè)?jīng)學(xué)過(guò)的設(shè)計(jì)模式扒出來(lái),看使用哪種模式能讓它看起來(lái)更優(yōu)雅一點(diǎn)。

三、責(zé)任鏈模式+建造者模式

我們看建造型設(shè)計(jì)模式的文章,看建造者模式中的典型應(yīng)用中的Lombok。

參考Lombok的 @Builder例子,是不是和我們這個(gè)有著些許相似呢?

我們?cè)贖andle的類中創(chuàng)建一個(gè)Builder內(nèi)部類。

/**
 * 建造者模式
 */
public static class Builder{
    private Handler head;
    private Handler tail;

    public Builder addHanlder(Handler handler){
        //head==null表示第一次添加到隊(duì)列
        if (null == head){
            head = this.tail = handler;
            return this;
        }
        //原tail節(jié)點(diǎn)指向新添加進(jìn)來(lái)的節(jié)點(diǎn)
        this.tail.setNext(handler);
        //新添加進(jìn)來(lái)的節(jié)點(diǎn)設(shè)置為tail節(jié)點(diǎn)
        this.tail = handler;
        return this;
    }

    public Handler build(){
        return this.head;
    }
}

該內(nèi)部類更像是一個(gè)鏈表結(jié)構(gòu),定義一個(gè)頭和尾對(duì)象,add方法是向鏈接的頭尾中賦值,build返回頭元素方便開(kāi)始鏈?zhǔn)秸{(diào)用。我們對(duì)調(diào)用方代碼進(jìn)行改造。

//建造者模式---------
public static void main(String[] args) {
    Handler.Builder builder = new Handler.Builder();
    builder.addHanlder(new ConcreteHandlerUsername())
            .addHanlder(new ConcreteHandlerPassword());
    builder.build().handle("用戶名tcy");

}

這樣的實(shí)現(xiàn)方式比原方式優(yōu)雅多了。責(zé)任鏈模式本身是很簡(jiǎn)單的,如果將責(zé)任鏈模式和建造者模式組合起來(lái)使用就沒(méi)那么容易理解了。

在實(shí)際使用中往往不是一個(gè)單一的設(shè)計(jì)模式,更多的是多種組合模式組成的“四不像”,實(shí)際上這并不是一件輕松的事。

四、責(zé)任鏈模式在源碼運(yùn)用

為了加深理解我們繼續(xù)深入責(zé)任鏈模式在Spring中的運(yùn)用。

Spring Web 中的 HandlerInterceptor,里面有preHandle()、postHandle()afterCompletion()三個(gè)方法,實(shí)現(xiàn)這三個(gè)方法可以分別在調(diào)用"Controller"方法之前,調(diào)用"Controller"方法之后渲染"ModelAndView"之前,以及渲染"ModelAndView"之后執(zhí)行。

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 {
    }

}

HandlerInterceptor就是角色中的抽象處理者,HandlerExecutionChain相當(dāng)于上述中的Client,用于調(diào)用責(zé)任鏈上的各個(gè)環(huán)節(jié)。

public class HandlerExecutionChain {
...

@Nullable
private HandlerInterceptor[] interceptors;

private int interceptorIndex = -1;

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HandlerInterceptor[] interceptors = getInterceptors();
    if (!ObjectUtils.isEmpty(interceptors)) {
        for (int i = 0; i < interceptors.length; i++) {
            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--) {
            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 {
                interceptor.afterCompletion(request, response, this.handler, ex);
            }
            catch (Throwable ex2) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
            }
        }
    }
}
}

私有的數(shù)組 private HandlerInterceptor[] interceptors 用于存儲(chǔ)責(zé)任鏈的每個(gè)環(huán)節(jié),,然后通過(guò)interceptorIndex作為指針去遍歷責(zé)任鏈數(shù)組按順序調(diào)用處理者。

結(jié)合我們上面給出的例子,在Spring中的應(yīng)用是比較容易理解的。

在Servlet的一系列攔截器也是采用的責(zé)任鏈模式,有興趣的讀者可以深入研究一下。

五、總結(jié)

當(dāng)必須按順序執(zhí)行多個(gè)處理者時(shí),可以考慮使用責(zé)任鏈模式。如果處理者的順序及其必須在運(yùn)行時(shí)改變時(shí),可以考慮使用責(zé)任鏈模式。責(zé)任鏈的模式是缺點(diǎn)也很明顯,增加了系統(tǒng)的復(fù)雜性。

但是要切忌避免過(guò)度設(shè)計(jì),在實(shí)際應(yīng)用中,校驗(yàn)用戶名和密碼的業(yè)務(wù)邏輯并沒(méi)有那么的復(fù)雜,可能只是一個(gè)判斷語(yǔ)句,使用設(shè)計(jì)模式只會(huì)增加系統(tǒng)的復(fù)雜性,而在Shiro、SpringSecurity、SpringMVC的攔截器中使用責(zé)任鏈模式是一個(gè)好的選擇。

如果在你的項(xiàng)目業(yè)務(wù)中需要定義一系列攔截器,那么使用責(zé)任鏈模式就是一個(gè)比較不錯(cuò)的選擇。

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • Spring中PathMatcher路徑匹配器的實(shí)現(xiàn)

    Spring中PathMatcher路徑匹配器的實(shí)現(xiàn)

    Spring框架中的PathMatcher是一個(gè)接口,本文主要介紹了Spring中PathMatcher路徑匹配器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • RabbitMQ中的死信隊(duì)列(Dead Letter Exchanges)詳解

    RabbitMQ中的死信隊(duì)列(Dead Letter Exchanges)詳解

    這篇文章主要介紹了RabbitMQ中的死信隊(duì)列(Dead Letter Exchanges)詳解,當(dāng)RabbitMQ出現(xiàn)死信,可能會(huì)導(dǎo)致業(yè)務(wù)邏輯錯(cuò)誤,比如下訂單后修改庫(kù)存操作,在下單后因?yàn)槟撤N原因,發(fā)送的消息未被簽收,這時(shí)庫(kù)存數(shù)據(jù)會(huì)出現(xiàn)不一致,需要的朋友可以參考下
    2023-12-12
  • 多jdk環(huán)境下指定springboot外部配置文件詳解

    多jdk環(huán)境下指定springboot外部配置文件詳解

    這篇文章主要為大家介紹了多jdk環(huán)境下指定springboot外部配置文件詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Java線程操作的常見(jiàn)方法【線程名稱獲取、設(shè)置、線程啟動(dòng)判斷等】

    Java線程操作的常見(jiàn)方法【線程名稱獲取、設(shè)置、線程啟動(dòng)判斷等】

    這篇文章主要介紹了Java線程操作的常見(jiàn)方法,結(jié)合實(shí)例形式總結(jié)分析了java線程的創(chuàng)建、線程名稱的獲取、設(shè)置以及線程啟動(dòng)的判斷等相關(guān)操作實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-10-10
  • Java日期處理工具類DateUtils詳解

    Java日期處理工具類DateUtils詳解

    這篇文章主要為大家詳細(xì)介紹了Java日期處理工具類DateUtils的相關(guān)代碼,包含日期和時(shí)間常用操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • JVM GC 垃圾收集梳理總結(jié)

    JVM GC 垃圾收集梳理總結(jié)

    這篇文章主要介紹了JVM GC 垃圾收集梳理總結(jié),GC是一種自動(dòng)的存儲(chǔ)管理機(jī)制。當(dāng)一些被占用的內(nèi)存不再需要時(shí),就應(yīng)該予以釋放,這種存儲(chǔ)資源管理,稱為垃圾回收
    2022-07-07
  • Java 實(shí)現(xiàn)跨平臺(tái)的操作方式

    Java 實(shí)現(xiàn)跨平臺(tái)的操作方式

    這篇文章主要介紹了Java 實(shí)現(xiàn)跨平臺(tái)的操作方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • java字符緩沖流面試精講

    java字符緩沖流面試精講

    這篇文章主要為大家介紹了java中字符緩沖流面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    Java使用EasyExcel進(jìn)行單元格合并的問(wèn)題詳解

    項(xiàng)目中需要導(dǎo)出并合并指定的單元格,下面這篇文章主要給大家介紹了關(guān)于java評(píng)論、回復(fù)功能設(shè)計(jì)與實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Idea2020 無(wú)法share項(xiàng)目到svn的解決方法

    Idea2020 無(wú)法share項(xiàng)目到svn的解決方法

    這篇文章主要介紹了Idea2020 無(wú)法share項(xiàng)目到svn的解決方法,需要的朋友可以參考下
    2020-09-09

最新評(píng)論