最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
這就是『責(zé)任鏈模式』?

前言

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比姜堰網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式姜堰網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋姜堰地區(qū)。費(fèi)用合理售后完善,10年實(shí)體公司更值得信賴。

只有光頭才能變強(qiáng)。

文本已收錄至我的GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3y

最近在看項(xiàng)目代碼的時(shí)候發(fā)現(xiàn)「責(zé)任鏈模式」,于是想花點(diǎn)時(shí)間來寫寫什么是責(zé)任鏈模式。

不知道大家是怎么學(xué)習(xí)設(shè)計(jì)模式的,一般我都是用到的時(shí)候,或者接觸到的時(shí)候才會(huì)去學(xué)。否則感覺學(xué)完就很容易就忘掉了,不能理解為什么要使用設(shè)計(jì)模式(因?yàn)闆]有真實(shí)的場(chǎng)景給我去使用)。

在之前我已經(jīng)更新說幾篇設(shè)計(jì)模式的文章了,我覺得寫得「還行」,有興趣的同學(xué)可以到我的GitHub上,關(guān)鍵字搜索「設(shè)計(jì)模式」,就能找到對(duì)應(yīng)的文章。

這就是『責(zé)任鏈模式』?
這就是『責(zé)任鏈模式』?

不得不說,我現(xiàn)在負(fù)責(zé)項(xiàng)目的代碼我常常會(huì)感嘆:這代碼怎么這么騷??!項(xiàng)目里邊用到了很多的設(shè)計(jì)模式,在最開始看的時(shí)候會(huì)很費(fèi)勁(因?yàn)橹皼]學(xué)),但維護(hù)起來是真的方便。

一、什么是責(zé)任鏈模式?

在說責(zé)任鏈模式之前,我們先來聊聊「過濾器」。

過濾器相信大家都肯定學(xué)過了,在最開始學(xué)Servlet的時(shí)候我們會(huì)學(xué)到Filter。等學(xué)到Struts2的時(shí)候,我們會(huì)學(xué)到Interceptor。等學(xué)到SpringMVC的時(shí)候,我們會(huì)學(xué)到HandlerInterceptor。

但無論學(xué)哪個(gè)框架,我們發(fā)現(xiàn)是最終其實(shí)它還是做Filter這么一件事。說白了就是:

  • 把所有的過濾器都放在FilterChain里邊,依次執(zhí)行每個(gè)過濾器。

在我的GitHub對(duì)Filter,HandlerInterceptor,Interceptor都有講到,如果想要復(fù)習(xí)的同學(xué)不妨進(jìn)去搜索關(guān)鍵字「過濾器」「Struts2」「SpringMVC

這就是『責(zé)任鏈模式』?

為什么看責(zé)任鏈模式要聊「過濾器」呢?后面會(huì)講到,不要著急。

1.1 干掉敖丙和雞蛋

舉個(gè)例子:把我們的正常請(qǐng)求想象成一堆的雜物,里邊有米豆,有雞蛋,有敖丙公仔玩具等等一些雜物。

這就是『責(zé)任鏈模式』?

現(xiàn)在我們想要最后得到的是米豆,雞蛋和敖丙玩具都被過濾掉。于是我們就可以搞兩個(gè)濾網(wǎng),把敖丙玩具和雞蛋給過濾掉。

以最快的方式,我們可以寫if來把這個(gè)需求給搞掂,下面上代碼。

一個(gè)請(qǐng)求,我們使用Request對(duì)象來表示:

public class Request {
    // 請(qǐng)求的數(shù)據(jù)
    private String data;

    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

針對(duì)請(qǐng)求,我們肯定是有一個(gè)接口處理請(qǐng)求的啦,我們使用Handler來表示:

public class Handler {

    public void handlerRequest(Request request) {

        // 得到請(qǐng)求的數(shù)據(jù)
        String data = request.getData();

        if (data.contains("雞蛋")) {
            filterEgg(data);
        }
        if (data.contains("敖丙工具")) {
            filterAoBing(data);
        }
        // 我到這里就能拿到米豆了。
    }

    private void filterAoBing(String data) {
        //doSomething
    }

    private void filterEgg(String data) {
        //doSomething
    }
}

上面的代碼大家不知道熟不熟悉,反正我就很熟悉,很多時(shí)候我就是這樣寫代碼的(在現(xiàn)實(shí)里邊很多代碼就是這樣的)。

1.2 如何更加優(yōu)雅干掉敖丙和雞蛋?

在某年某月產(chǎn)品過來告訴我,需要新增一種類型想要過濾的「白菜」

在某年某月產(chǎn)品過來告訴我,需要新增一種類型想要過濾的「雞腿」

在某年某月產(chǎn)品過來告訴我,需要新增一種類型想要過濾的「雞頭」

于是我們的Handler處理就可能「膨脹」起來了,可能是這樣?

public class Handler {

    public void handlerRequest(Request request) {

        // 得到請(qǐng)求的數(shù)據(jù)
        String data = request.getData();

        if (data.contains("雞蛋")) {
            filterEgg(data);
        }
        if (data.contains("敖丙工具")) {
            filterAoBing(data);
        }
        if (data.contains("白菜")) {
            filterBaiCai(data);
        }
        if (data.contains("雞頭")) {
            filterJiTou(data);
        }
        if (data.contains("雞腿")) {
            filterJiTui(data);
        }
        // 我到這里就能拿到米豆了。
    }

    private void filterJiTou(String data) {
        //doSomething
    }

    private void filterJiTui(String data) {
        //doSomething
    }

    private void filterAoBing(String data) {
        //doSomething
    }

    private void filterEgg(String data) {
        //doSomething
    }
}

明顯的是,如果處理的流程改動(dòng)比較大的話(需要增刪改其中的某個(gè)流程),那我每次都需要更改handlerRequest的代碼,增加/修改/刪除一個(gè)if和一個(gè)處理方法。

更加面向?qū)ο?/strong>的方式是這樣的:將每個(gè)處理的方式抽象成一個(gè)類,每個(gè)類各司其職。

無論是過濾敖丙還是過濾雞蛋還是過濾米豆,做的事都是過濾。我們就可以將其抽象成接口。于是我們就有一個(gè)接口,多個(gè)實(shí)現(xiàn)類。

public interface Filter {
    // 過濾
    void doFilter(String data);
}

class FilterEgg implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterAoBing implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterBaiCai implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterJiTou implements Filter {

    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

每個(gè)各司其職的Filter都有可能被執(zhí)行,我們可以將其串成一條鏈,抽象一層對(duì)外只暴露一個(gè)方法來替代if。于是我們可以寫出一個(gè)FilterChain

public class FilterChain {
    List filters = new ArrayList<>();

    public FilterChain() {
        filters.add(new FilterEgg());
        filters.add(new FilterAoBing());
        filters.add(new FilterBaiCai());
        filters.add(new FilterJiTou());
    }
    public void processData(String data) {
        for (Filter filter : filters) {
            filter.doFilter(data);
        }
    }
}

改造過后,我們的Handler就長(zhǎng)這個(gè)樣子了:

public class Handler {
    public void handlerRequest(Request request) {
        // 得到請(qǐng)求的數(shù)據(jù)
        String data = request.getData();
        FilterChain filterChain = new FilterChain();
        // 處理數(shù)據(jù)
        filterChain.processData(data);
    }
}

如果我告訴你,這種的處理方式就是責(zé)任鏈模式,你會(huì)怎么想?

二、為什么責(zé)任鏈模式?

再來回顧一下,我做了些什么:

  1. 將處理的各個(gè)流程抽象為各個(gè)類(本來Handler里邊有多個(gè)if方法)

  2. 將多個(gè)類用Chain鏈起來,暴露一個(gè)方法給Handler使用

  3. done

下面我畫了一張對(duì)比圖:

這就是『責(zé)任鏈模式』?

是不是很簡(jiǎn)單?說到底還是抽象了一層(將每個(gè)處理抽象為一個(gè)類而已)。

這就是『責(zé)任鏈模式』?

那為什么要這樣干?如果我要增加一個(gè)處理流程,我是得新增一個(gè)處理類,然后在鏈上增加相對(duì)應(yīng)的類。操作也的確如此。

這不麻煩嗎?要便捷的話,我還不如直接增加一個(gè)if,一個(gè)處理方法來得方便呢。

用責(zé)任鏈模式的好處就是分工明確,解耦,容易維護(hù)

  • 將多個(gè)條件判定分散到各個(gè)的處理類上,相對(duì)于if else耦合性相對(duì)較低。

  • 增加一個(gè)具體的Handler處理類,不會(huì)影響到BaseHandler的代碼

責(zé)任鏈模式的缺點(diǎn):

  • 項(xiàng)目里邊會(huì)有多個(gè)具體Handler類(因?yàn)槊糠N處理都抽象為一個(gè)類,所以會(huì)有多個(gè)類)

  • 不好調(diào)試,初看代碼時(shí)不好閱讀。(對(duì)外只是一個(gè)doChain方法,而里邊由多個(gè)處理類來組成,還得看相應(yīng)的調(diào)用順序)

三、再來聊聊責(zé)任鏈模式

我們從上面也可以看到責(zé)任鏈模式主要有以下特點(diǎn):

  • 一個(gè)Handler接口,多個(gè)Handler處理類

  • 多個(gè)Handler處理類串起來形成一條鏈

有這兩個(gè)特點(diǎn)我就稱這些代碼運(yùn)用了責(zé)任鏈模式。在翻閱資料或者看書的時(shí)候,你可能會(huì)看到:“責(zé)任鏈和不純責(zé)任鏈”

  • 純:請(qǐng)求執(zhí)行到某個(gè)具體的Handler,該Handler要么自行處理然后結(jié)束請(qǐng)求,要么不處理繼續(xù)往下給別的Handler執(zhí)行。

  • 不純:請(qǐng)求執(zhí)行到某個(gè)具體的Handler,該Handler自行處理了,繼續(xù)往下給別的Handler執(zhí)行。

還有就是將各個(gè)具體的Handler串成一條鏈,這里邊的實(shí)現(xiàn)會(huì)有各式各樣的:

  • 在我例子里是直接new出一個(gè)ArrayList,然后在構(gòu)造方法里邊代碼手動(dòng)add到ArrayList的

  • 有可能會(huì)在代碼里邊每個(gè)具體Handler都會(huì)記錄自己下一個(gè)Handler是誰

  • 有可能將Handler的初始化放在XML上

  • ….//反正各種操作最終還是會(huì)將各個(gè)Handler串起來。

其實(shí)不必要在意純和不純的責(zé)任鏈模式,我們學(xué)設(shè)計(jì)模式是為了學(xué)它的思想。

四、看看JavaWeb的Filter

在文章最開頭我就說了我們以前學(xué)過的Filter,其實(shí)Filter就是用了責(zé)任鏈模式。我們來簡(jiǎn)單看看代碼:

我們?cè)谑褂肍ilter過濾器的時(shí)候,要么在XML上配置,要么在代碼上寫上注解@WebFilter(filterName = "",urlPatterns = "")

這些配置都會(huì)在Web容器啟動(dòng)的時(shí)候被讀取,讀完這些配置,會(huì)將你寫的Filter過濾器加到FilterChain里邊:

這就是『責(zé)任鏈模式』?

我們可以看到Filter接口下有很多都實(shí)現(xiàn)了doFilter

這就是『責(zé)任鏈模式』?

JavaWeb的Filter實(shí)際用到的也是責(zé)任鏈模式。

最后

設(shè)計(jì)模式本身不是一件很復(fù)雜的東西,像門面模式,模板方法模式都非常容易理解。學(xué)完了會(huì)有一種感覺:“?。烤瓦@?

重要的是學(xué)完能不能用到實(shí)際的工作中,這是非常難能可貴的。我們寫代碼按照自身的思維寫if else是非常簡(jiǎn)單的,而設(shè)計(jì)模式往往需要繞一個(gè)圈才能把功能實(shí)現(xiàn)。

但是,合理運(yùn)用設(shè)計(jì)模式的代碼是非常好維護(hù)的。如果你懂設(shè)計(jì)模式,那代碼會(huì)看起來非常清晰。如果你不懂設(shè)計(jì)模式,你就會(huì)感嘆“這代碼是真的騷阿”(這就是我…)。

好好學(xué)習(xí),希望有朝一日,別人看到我的代碼,在背后說「這人寫的代碼是真的騷,牛逼阿」。

參考資料:

  • 《設(shè)計(jì)模式之禪》

  • https://www.cnblogs.com/tanshaoshenghao/p/10741160.html

  • 如果大家想要實(shí)時(shí)關(guān)注我更新的文章以及分享的干貨的話,可以關(guān)注我的公眾號(hào)Java3y。


分享文章:這就是『責(zé)任鏈模式』?
分享鏈接:http://fisionsoft.com.cn/article/jhhjcg.html