【設(shè)計模式(13)】行為型模式之責(zé)任鏈模式

個人學(xué)習(xí)筆記分享,當(dāng)前能力有限,請勿貶低,菜鳥互學(xué),大佬繞道

如有勘誤,歡迎指出和討論,本文后期也會進行修正和補充


前言

在我上個公司,如果需要請假一天,只需要獲取組長同意就可以了,通知一下人事就溜;但是如果長于1天不超過3天,那么需要跟項目經(jīng)理說明情況,獲得允許,同樣需要告知人事部;長于3天則需要獲得部門經(jīng)理的同意,再告知人事;

也就是說,如果要請假我得先知道這些規(guī)則,并且知道所有領(lǐng)導(dǎo)的姓名和練習(xí)方式,小公司還好,大公司這可就麻煩了。

很多公司采取的方式是跟自己的直屬上司匯報即可,比如我報備給組長,組長如果沒權(quán)限就繼續(xù)上報給項目經(jīng)理,項目經(jīng)理沒權(quán)限就上報給經(jīng)理,最終我得到答復(fù)即可。

當(dāng)然其實這樣如果責(zé)任分配不合理,很容易出現(xiàn)踢皮球的問題,比如前段時間出現(xiàn)的新聞,如何證明我爸是我爸?


在開發(fā)中,攔截器也是如此處理,攔截器會按照規(guī)則攔截請求,并將其按照設(shè)定好的指責(zé)鏈傳遞,由每個節(jié)點決定轉(zhuǎn)發(fā)給下一層或者直接拒絕掉。

同理還有JS的冒泡機制,觸發(fā)的事件會從最里層逐步往上冒泡,因此我們可以對于一個事件針對不同情況處理。


責(zé)任鏈(Chain of Responsibility)模式的定義:為了避免請求發(fā)送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一對象記住其下一個對象的引用而連成一條鏈;當(dāng)有請求發(fā)生時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。

在責(zé)任鏈模式中,客戶只需要將請求發(fā)送到責(zé)任鏈上即可,無須關(guān)心請求的處理細(xì)節(jié)和請求的傳遞過程,所以責(zé)任鏈將請求的發(fā)送者和請求的處理者解耦了


1.介紹

使用目的:將請求發(fā)送者與接收者解耦,發(fā)送者不需要知道實際處理流程。

主要解決:一個發(fā)送者有多個接受者時,耦合度較高,擴展起來會很麻煩,靈活度極低

如何解決:在攔截類中設(shè)定下個接受者。

實現(xiàn)方法:攔截的類實現(xiàn)統(tǒng)一接口,并指定下一個接受者,收到請求后先處理,再判斷是否傳給下個接受者

應(yīng)用實例:

  • JS中的事件冒泡
  • servlet的攔截器
  • AOP切面攔截器

優(yōu)點:

  • 請求的發(fā)送者和接收者解耦,耦合度較低
  • 發(fā)送者不知道責(zé)任鏈內(nèi)部邏輯,只需要調(diào)用接口即可,簡化了使用流程
  • 允許動態(tài)的修改職責(zé)的順序和內(nèi)容,也能動態(tài)的新增職責(zé)節(jié)點,靈活度高

缺點:

  • 不能保證請求一定被接收
  • 設(shè)計不當(dāng)時可能出現(xiàn)死循環(huán),即鏈變成環(huán)
  • 責(zé)任鏈組裝過程在客戶端中完成,增加了客戶端的復(fù)雜性,也提高了出錯的可能性

使用場景:

  • 有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定。
  • 在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
  • 可動態(tài)指定一組對象處理請求。


2.結(jié)構(gòu)

職責(zé)鏈模式主要包含以下角色

  • 抽象處理者(Handler)角色:定義一個處理請求的接口,包含抽象處理方法和一個后繼連接。
  • 具體處理者(Concrete Handler)角色:實現(xiàn)抽象處理者的處理方法,判斷能否處理本次請求,如果可以處理請求則處理,否則將該請求轉(zhuǎn)給它的后繼者。
  • 客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對象提交請求,它不關(guān)心處理細(xì)節(jié)和請求的傳遞過程。
image-20201030121957438
  • 所有的具體處理者都需要實現(xiàn)抽象處理者
  • 抽象處理者會持有下一個抽象處理者對象


3.實現(xiàn)步驟

  1. 定義抽象處理者

    abstract class Handler {
        public static final int LEVEL_1 = 1;
        public static final int LEVEL_2 = 2;
        public static final int LEVEL_3 = 3;
    
        private Handler next;
        private int level;
    
        public Handler(int level, Handler next) {
            this.level = level;
            this.next = next;
        }
    
        //處理請求的方法
        public void handleRequest(int level, String arg) {
            if (this.level == level) {
                handle(arg);
            } else {
                if (null != next) {
                    next.handleRequest(level, arg);
                } else {
                    System.out.println("no suitable handle");
                }
            }
        }
    
        //處理者自身方法
        public abstract void handle(String arg);
    }
    

核心是handleRequest(int level, String arg)方法,需要決定是自行處理,或者傳遞到下一個處理者,或者終止

  1. 定義具體處理者

    //具體處理者角色1
    class ConcreteHandler1 extends Handler {
        public ConcreteHandler1(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler1 handled this request!" + arg);
        }
    }
    
    //具體處理者角色2
    class ConcreteHandler2 extends Handler {
        public ConcreteHandler2(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler2 handled this request!" + arg);
        }
    }
    
    //具體處理者角色2
    class ConcreteHandler3 extends Handler {
        public ConcreteHandler3(int level, Handler next) {
            super(level, next);
        }
    
        @Override
        public void handle(String arg) {
            System.out.println("ConcreteHandler3 handled this request!" + arg);
        }
    }
    
  2. 客戶端組裝責(zé)任鏈

    public static Handler getChain() {
        Handler concreteHandler1 = new ConcreteHandler1(1, null);
        Handler concreteHandler2 = new ConcreteHandler2(2, concreteHandler1);
        Handler concreteHandler3 = new ConcreteHandler3(3, concreteHandler2);
        return concreteHandler3;
    }
    

完整代碼

package com.company.test.chainPattern;

//抽象處理者角色
abstract class Handler {
    public static final int LEVEL_1 = 1;
    public static final int LEVEL_2 = 2;
    public static final int LEVEL_3 = 3;

    private Handler next;
    private int level;

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

    //處理請求的方法
    public void handleRequest(int level, String arg) {
        if (this.level == level) {
            handle(arg);
        } else {
            if (null != next) {
                next.handleRequest(level, arg);
            } else {
                System.out.println("no suitable handle");
            }
        }
    }

    //處理者自身方法
    public abstract void handle(String arg);
}

//具體處理者角色1
class ConcreteHandler1 extends Handler {
    public ConcreteHandler1(int level, Handler next) {
        super(level, next);
    }

    @Override
    public void handle(String arg) {
        System.out.println("ConcreteHandler1 handled this request!" + arg);
    }
}

//具體處理者角色2
class ConcreteHandler2 extends Handler {
    public ConcreteHandler2(int level, Handler next) {
        super(level, next);
    }

    @Override
    public void handle(String arg) {
        System.out.println("ConcreteHandler2 handled this request!" + arg);
    }
}

//具體處理者角色2
class ConcreteHandler3 extends Handler {
    public ConcreteHandler3(int level, Handler next) {
        super(level, next);
    }

    @Override
    public void handle(String arg) {
        System.out.println("ConcreteHandler3 handled this request!" + arg);
    }
}

public class ChainPatternDemo {
    public static Handler getChain() {
        Handler concreteHandler1 = new ConcreteHandler1(1, null);
        Handler concreteHandler2 = new ConcreteHandler2(2, concreteHandler1);
        Handler concreteHandler3 = new ConcreteHandler3(3, concreteHandler2);
        return concreteHandler3;
    }

    public static void main(String[] args) {
        Handler handler = getChain();

        System.out.println("--------------------------- handle request level 1 ------------------------------");
        handler.handleRequest(Handler.LEVEL_1, " test round 1");
        System.out.println("--------------------------- handle request level 2 ------------------------------");
        handler.handleRequest(Handler.LEVEL_2, " test round 2");
        System.out.println("--------------------------- handle request level 3 ------------------------------");
        handler.handleRequest(Handler.LEVEL_3, " test round 3");
    }
}

運行結(jié)果

image-20201030140622194

4.示例

模擬請假審批

  • 組長可審批1天以內(nèi)請假
  • 項目經(jīng)理可以審批3天以內(nèi)請假
  • 部門經(jīng)理可以審批7天以內(nèi)請假
package com.company.test.chainPattern;

//抽象處理者角色
abstract class LeaveHandler {
    public static final int DURATION_LEADER = 1;
    public static final int DURATION_PROJECT_MANAGER = 3;
    public static final int DURATION_DIVISION_MANAGER = 7;

    private LeaveHandler next;
    protected int days;

    public LeaveHandler(LeaveHandler next) {
        this.next = next;
    }

    //處理請求的方法
    public void handleRequest(int days, String arg) {
        if (days <= this.days) {
            handle(arg);
        } else {
            if (null != next) {
                next.handleRequest(days, arg);
            } else {
                System.out.println("無人受理請假申請!" + arg);
            }
        }
    }

    //處理者自身方法
    public abstract void handle(String arg);
}

//具體處理者角色1
class LeaderHandler extends LeaveHandler {
    public LeaderHandler(LeaveHandler next) {
        super(next);
        this.days = LeaveHandler.DURATION_LEADER;
    }

    @Override
    public void handle(String arg) {
        System.out.println("Leader approved this request!" + arg);
    }
}

//具體處理者角色2
class GroupManagerHandler extends LeaveHandler {
    public GroupManagerHandler(LeaveHandler next) {
        super(next);
        this.days = LeaveHandler.DURATION_PROJECT_MANAGER;
    }

    @Override
    public void handle(String arg) {
        System.out.println("Group manager approved this request!" + arg);
    }
}

//具體處理者角色2
class DivisionManagerHandler extends LeaveHandler {
    public DivisionManagerHandler(LeaveHandler next) {
        super(next);
        this.days = LeaveHandler.DURATION_DIVISION_MANAGER;
    }

    @Override
    public void handle(String arg) {
        System.out.println("Division manager approved this request!" + arg);
    }
}

public class ChainPatternDemo2 {
    public static LeaveHandler getChain() {
        LeaveHandler divisionManagerHandler = new DivisionManagerHandler(null);
        LeaveHandler groupManagerHandler = new GroupManagerHandler(divisionManagerHandler);
        LeaveHandler leaderHandler = new LeaderHandler(groupManagerHandler);
        return leaderHandler;
    }

    public static void main(String[] args) {
        LeaveHandler handler = getChain();

        handler.handleRequest(1, " 請假1天");
        handler.handleRequest(2, " 請假2天");
        handler.handleRequest(3, " 請假3天");
        handler.handleRequest(10, " 請假10天");
    }
}
image-20201030173651638

后記

責(zé)任鏈模式將組裝交給了客戶端去處理,一方面提高了自由度,另一方面也提高了出錯的可能性,比如自我嵌套會出現(xiàn)死循環(huán),需要在組裝責(zé)任鏈的時候謹(jǐn)慎操作。。。


作者:Echo_Ye

WX:Echo_YeZ

Email :echo_yezi@qq.com

個人站點:在搭了在搭了。。。(右鍵 - 新建文件夾)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容