Android事件分發(fā)流程(一)責(zé)任鏈設(shè)計(jì)模式

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

簡(jiǎn)單介紹

View的事件分發(fā)機(jī)制是責(zé)任鏈(Chain of Responsibility)設(shè)計(jì)模式的典型應(yīng)用,其它經(jīng)典的應(yīng)用場(chǎng)景還有:JavaWeb 的過濾器、攔截器,Servlet中的請(qǐng)求響應(yīng)鏈;okhttp開源庫(kù)中也是在網(wǎng)絡(luò)層、應(yīng)用層中使用攔截器來進(jìn)行分層解耦,使的網(wǎng)絡(luò)層的配置和開發(fā)變得簡(jiǎn)單而優(yōu)雅。

案例分析

設(shè)計(jì)模式并不是一個(gè)抽象的概念,而是在編程的實(shí)踐中總結(jié)出的用于解決某類典型問題的典型范式??梢哉f,設(shè)計(jì)模式是為實(shí)戰(zhàn)而生的。這里說的責(zé)任鏈設(shè)計(jì)模式也不例外,下面看一個(gè)真實(shí)的應(yīng)用場(chǎng)景:

員工請(qǐng)假流程,普通員工三天以內(nèi)的請(qǐng)假申請(qǐng),TeamLeader直接可以直接審批通過;三到五天的請(qǐng)假申請(qǐng)由TeamLeader審批通過后技術(shù)總監(jiān)(CTO)可以審批通過;五到十天的請(qǐng)假申請(qǐng)就必須得到技術(shù)總監(jiān)(CTO)的審批通過后部門經(jīng)理(PV)可以審批通過;而十天以上的請(qǐng)假申請(qǐng)就必須得到部門經(jīng)理(PV)總經(jīng)理(CEO)的審批通過后才能正常休假。
員工休假申請(qǐng),只需要找到自己的直接上級(jí)申請(qǐng)就可以了;直接上級(jí)可以拒絕員工的請(qǐng)假,如果請(qǐng)假時(shí)長(zhǎng)超出直接上級(jí)的審批范圍,直接上級(jí)可以向上提交該員工的請(qǐng)假申請(qǐng)。經(jīng)過具有批準(zhǔn)權(quán)限的兩級(jí)的批準(zhǔn),員工才可以正常休假。

實(shí)例流程,如下所示:

程序員提交了了角色為【程序員-小林】提交的休假請(qǐng)求;時(shí)長(zhǎng):【2】天。
項(xiàng)目組長(zhǎng)攔截了角色為【程序員-小林】提交的休假請(qǐng)求;時(shí)長(zhǎng):【2】天。
項(xiàng)目組長(zhǎng)已批準(zhǔn)角色為【程序員-小林】提交的休假請(qǐng)求;時(shí)長(zhǎng):【2】天。
程序員提交了了角色為【程序員-大鵬】提交的休假請(qǐng)求;時(shí)長(zhǎng):【3】天。
項(xiàng)目組長(zhǎng)提交了了角色為【程序員-大鵬】提交的休假請(qǐng)求;時(shí)長(zhǎng):【3】天。
技術(shù)經(jīng)理攔截了角色為【程序員-大鵬】提交的休假請(qǐng)求;時(shí)長(zhǎng):【3】天。
技術(shù)經(jīng)理已批準(zhǔn)角色為【程序員-大鵬】提交的休假請(qǐng)求;時(shí)長(zhǎng):【3】天。
程序員提交了了角色為【程序員-樊勝美】提交的休假請(qǐng)求;時(shí)長(zhǎng):【5】天。
項(xiàng)目組長(zhǎng)提交了了角色為【程序員-樊勝美】提交的休假請(qǐng)求;時(shí)長(zhǎng):【5】天。
技術(shù)經(jīng)理提交了了角色為【程序員-樊勝美】提交的休假請(qǐng)求;時(shí)長(zhǎng):【5】天。
部門經(jīng)理攔截了角色為【程序員-樊勝美】提交的休假請(qǐng)求;時(shí)長(zhǎng):【5】天。
部門經(jīng)理已批準(zhǔn)角色為【程序員-樊勝美】提交的休假請(qǐng)求;時(shí)長(zhǎng):【5】天。
程序員提交了了角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
項(xiàng)目組長(zhǎng)提交了了角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
技術(shù)經(jīng)理提交了了角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
部門經(jīng)理提交了了角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
首席執(zhí)行官攔截了角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
首席執(zhí)行官已批準(zhǔn)角色為【程序員-小蚯蚓】提交的休假請(qǐng)求;時(shí)長(zhǎng):【10】天。
項(xiàng)目組長(zhǎng)提交了了角色為【項(xiàng)目組長(zhǎng)-關(guān)關(guān)】提交的休假請(qǐng)求;時(shí)長(zhǎng):【12】天。
技術(shù)經(jīng)理提交了了角色為【項(xiàng)目組長(zhǎng)-關(guān)關(guān)】提交的休假請(qǐng)求;時(shí)長(zhǎng):【12】天。
部門經(jīng)理提交了了角色為【項(xiàng)目組長(zhǎng)-關(guān)關(guān)】提交的休假請(qǐng)求;時(shí)長(zhǎng):【12】天。
首席執(zhí)行官攔截了角色為【項(xiàng)目組長(zhǎng)-關(guān)關(guān)】提交的休假請(qǐng)求;時(shí)長(zhǎng):【12】天。
首席執(zhí)行官已批準(zhǔn)角色為【項(xiàng)目組長(zhǎng)-關(guān)關(guān)】提交的休假請(qǐng)求;時(shí)長(zhǎng):【12】天。
項(xiàng)目組長(zhǎng)提交了了角色為【項(xiàng)目組長(zhǎng)-應(yīng)勤】提交的休假請(qǐng)求;時(shí)長(zhǎng):【14】天。
技術(shù)經(jīng)理提交了了角色為【項(xiàng)目組長(zhǎng)-應(yīng)勤】提交的休假請(qǐng)求;時(shí)長(zhǎng):【14】天。
部門經(jīng)理提交了了角色為【項(xiàng)目組長(zhǎng)-應(yīng)勤】提交的休假請(qǐng)求;時(shí)長(zhǎng):【14】天。
首席執(zhí)行官攔截了角色為【項(xiàng)目組長(zhǎng)-應(yīng)勤】提交的休假請(qǐng)求;時(shí)長(zhǎng):【14】天。
首席執(zhí)行官已拒絕角色為【項(xiàng)目組長(zhǎng)-應(yīng)勤】提交的休假請(qǐng)求;時(shí)長(zhǎng):【14】天。
技術(shù)經(jīng)理提交了了角色為【技術(shù)經(jīng)理-張璇】提交的休假請(qǐng)求;時(shí)長(zhǎng):【20】天。
部門經(jīng)理提交了了角色為【技術(shù)經(jīng)理-張璇】提交的休假請(qǐng)求;時(shí)長(zhǎng):【20】天。
首席執(zhí)行官攔截了角色為【技術(shù)經(jīng)理-張璇】提交的休假請(qǐng)求;時(shí)長(zhǎng):【20】天。
首席執(zhí)行官已批準(zhǔn)角色為【技術(shù)經(jīng)理-張璇】提交的休假請(qǐng)求;時(shí)長(zhǎng):【20】天。
部門經(jīng)理提交了了角色為【部門經(jīng)理-包奕凡】提交的休假請(qǐng)求;時(shí)長(zhǎng):【60】天。
首席執(zhí)行官攔截了角色為【部門經(jīng)理-包奕凡】提交的休假請(qǐng)求;時(shí)長(zhǎng):【60】天。
首席執(zhí)行官已批準(zhǔn)角色為【部門經(jīng)理-包奕凡】提交的休假請(qǐng)求;時(shí)長(zhǎng):【60】天。
首席執(zhí)行官提交了了角色為【首席執(zhí)行官-曲筱綃】提交的休假請(qǐng)求;時(shí)長(zhǎng):【120】天。
Master攔截了角色為【首席執(zhí)行官-曲筱綃】提交的休假請(qǐng)求;時(shí)長(zhǎng):【120】天。
Master拒絕了角色為【首席執(zhí)行官-曲筱綃】提交的休假請(qǐng)求;時(shí)長(zhǎng):【120】天。

代碼設(shè)計(jì)

既然知曉了使用責(zé)任鏈解決問題,那么按照責(zé)任鏈的思想解決現(xiàn)實(shí)問題。抽象休假處理的接口,Java中接口定義規(guī)則。如下圖,IHandler接口聲明了三個(gè)方法,dispatch開頭的方法是提交請(qǐng)假申請(qǐng)的方法;onIntercept開頭的方法表示是否攔截處理這個(gè)休假申請(qǐng);handle開頭的方法表示處理這個(gè)請(qǐng)求,可以批準(zhǔn)和拒絕該申請(qǐng),自此休假申請(qǐng)不在向上級(jí)提交。

package me.ziuo.design_pattern.cop.employee;

/**
 * 
 * @author ziyuo
 * @Description 抽象出來的休假申請(qǐng)?zhí)幚斫涌? */
public interface IHandler {

    /**
     * 分發(fā)請(qǐng)假請(qǐng)求
     * @param askModel
     * @return 分發(fā)結(jié)果
     */
    boolean dispatchAsk(LeaveAskModel askModel);

    /**
     * 攔截請(qǐng)假請(qǐng)求
     * @param askModel
     * @return 攔截與否
     */
    boolean onInterceptAsk(LeaveAskModel askModel);
    /**
     * 處理請(qǐng)假請(qǐng)求
     * @param askModel
     * @return 是否批準(zhǔn)
     */
    boolean handleAsk(LeaveAskModel askModel);

}

LeaveAskModel 休假請(qǐng)求類,該數(shù)據(jù)模型里面保存了修改的天數(shù)和申請(qǐng)人信息。如圖所示。

package me.ziuo.design_pattern.cop.employee;

/**
 * 
 * @author ziyuo
 * @Description 代表請(qǐng)假申請(qǐng)信息對(duì)象
 */
public class LeaveAskModel {
    private int days;// 休假天數(shù)
    private Employee askEmp;// 申請(qǐng)人

    public LeaveAskModel(int days, Employee askEmp) {
        super();
        this.days = days;
        this.askEmp = askEmp;
    }

    public int getDays() {
        return days;
    }

    public void setDays(int days) {
        this.days = days;
    }

    public Employee getAskEmp() {
        return askEmp;
    }

    public void setAskEmp(Employee askEmp) {
        this.askEmp = askEmp;
    }

}

員工的抽象類實(shí)現(xiàn)IHandler里面的定義的接口的相關(guān)的方法,里面包含了員工角色信息、員工名稱信息、可處理的最大申請(qǐng)?zhí)鞌?shù)、直屬領(lǐng)導(dǎo)(當(dāng)無權(quán)限處理休假申請(qǐng)的時(shí)候可以向上提交)。
其中實(shí)現(xiàn)IHandler的方法介紹
dispatch開頭的方法的具體含義是首先判斷本角色是否攔截這個(gè)請(qǐng)求,如果攔截則調(diào)用請(qǐng)求的方法,是否審批通過取決于handleAsk的結(jié)果。
onIntercept開頭方法的具體含義,是當(dāng)角色類型是否不同于提交的對(duì)象時(shí),如果提交者申請(qǐng)的提交時(shí)長(zhǎng)可以處理的情況下,選擇攔截該請(qǐng)求后請(qǐng)求響應(yīng)的審批處理。
handle開頭的方法用于進(jìn)行審批請(qǐng)求,邏輯大概是這樣:根據(jù)員工的信息來進(jìn)行響應(yīng)的處理,這里只是一個(gè)實(shí)現(xiàn)案例。
如圖所示。

package me.ziuo.design_pattern.cop.employee;

public abstract class Employee implements IHandler{
    
    private String actor;//員工角色名稱
    private String name;//員工名稱
    private int maxHandleDay;//最大可審批的請(qǐng)假天數(shù)(不包含最大天數(shù))
    
    private Employee leader;//直屬領(lǐng)導(dǎo)

    public Employee(String actor, int maxHandleDay) {
        super();
        this.actor = actor;
        this.maxHandleDay = maxHandleDay;
    }
    
    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    public int getMaxHandleDay() {
        return maxHandleDay;
    }

    public void setMaxHandleDay(int maxHandleDay) {
        this.maxHandleDay = maxHandleDay;
    }

    public boolean dispatchAsk(LeaveAskModel askModel) {
        if(onInterceptAsk(askModel)){
            return handleAsk(askModel);
        }else{
            if(getLeader()!=null){
                System.out.println(getActor()+"提交了了角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
                return getLeader().dispatchAsk(askModel);
            }else{
                System.out.println(getActor()+"提交了了角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
                
                //寫這段代碼的程序員進(jìn)行審批 ,終于站在了食物鏈的頂端(原來是在做夢(mèng))。
                System.out.println("【代碼作者】"+"攔截了角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
                System.out.println("【代碼作者】"+"拒絕了角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
                return false;
            }
        }
    }

    public boolean onInterceptAsk(LeaveAskModel askModel) {
        
        if(askModel!=null&&!this.getClass().equals(askModel.getAskEmp().getClass())&&askModel.getDays()<this.getMaxHandleDay()){
            System.out.println(getActor()+"攔截了角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
            return true;
        }
        return false;
    }

    public boolean handleAsk(LeaveAskModel askModel) {
        if(askModel==null||askModel.getAskEmp().getName().equals("小帥哥0")){
            System.out.println(getActor()+"已拒絕角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
            return false;
        }
        if(askModel!=null&&askModel.getDays()<this.getMaxHandleDay()){
            System.out.println(getActor()+"已批準(zhǔn)角色為【"+askModel.getAskEmp().actor+"】提交的休假請(qǐng)求;時(shí)長(zhǎng):【"+askModel.getDays()+"】天。");
            return true;
        }

        return false;
    }
    

    public Employee getLeader() {
        return leader;
    }

    public void setLeader(Employee leader) {
        this.leader = leader;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

各個(gè)對(duì)象的封裝案例,下面列出來。
程序員類代碼

package me.ziuo.design_pattern.cop.employee;

public class Programmer extends Employee {
    public Programmer() {
        this("程序員", 0);
    }

    public Programmer(String actor, int maxHandleDay) {
        super("程序員", 0);
        setLeader(new TeamLeader());
    }
    
    public boolean dispatchAsk(LeaveAskModel askModel) {
        return super.dispatchAsk(askModel);
    }
    
    public boolean onInterceptAsk(LeaveAskModel askModel) {
        return !(askModel.getAskEmp() instanceof Programmer);
    }

}

TeamLeader類代碼

package me.ziuo.design_pattern.cop.employee;

public class TeamLeader extends Employee {

    public TeamLeader() {
        this("項(xiàng)目組長(zhǎng)", 3);
    }
    public TeamLeader(String actor, int maxHandleDay) {
        super("項(xiàng)目組長(zhǎng)", 3);
        setLeader(new CTO());
    }
    
}

CTO類代碼

package me.ziuo.design_pattern.cop.employee;

public class CTO extends Employee {

    public CTO() {
        this("技術(shù)經(jīng)理", 5);
    }

    public CTO(String actor, int maxHandleDay) {
        super("技術(shù)經(jīng)理", 5);
        setLeader(new PV());
    }
    
}

PV類代碼

package me.ziuo.design_pattern.cop.employee;

public class PV extends Employee {

    public PV(){
        this("部門經(jīng)理", 10);
    }
    public PV(String actor, int maxHandleDay) {
        super("部門經(jīng)理", 10);
        setLeader(new CEO());
    }

}

CEO類代碼

package me.ziuo.design_pattern.cop.employee;

public class CEO extends Employee {

    public CEO(){
        this("首席執(zhí)行官", 120);
    }
    public CEO(String actor, int maxHandleDay) {
        super("首席執(zhí)行官", 120);
        setLeader(null);
    }
    
}

各個(gè)角色的向上傳遞休假申請(qǐng)的處理鏈,就組成了所謂的責(zé)任鏈;除了頂層的CEO其余的角色都持有他的直接領(lǐng)導(dǎo)。這條持有直接領(lǐng)導(dǎo)的鏈條就組成了一個(gè)單向鏈表,而責(zé)任鏈模式的部分場(chǎng)景中會(huì)直接使用單向的鏈表來鏈接責(zé)任處理集合。
責(zé)任鏈設(shè)計(jì)模到此就介紹完畢了。


如果希望了解Android事件分發(fā)流程對(duì)責(zé)任鏈設(shè)計(jì)模式的運(yùn)用請(qǐng)移步下面的鏈接。
Android事件分發(fā)流程(二)源碼解析

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

相關(guān)閱讀更多精彩內(nèi)容

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