設(shè)計模式整理(8) 責(zé)任鏈模式

學(xué)習(xí)《Android 源碼設(shè)計模式解析與實踐》系列筆記

介紹

所謂的鏈,是指將多個節(jié)點首尾相連形成的結(jié)構(gòu)泣特。
編程中的責(zé)任鏈模式,類似于這種結(jié)構(gòu)挑随,將每個節(jié)點看作是一個對象,每個對象擁有不同的處理邏輯兜挨,將一個請求從鏈?zhǔn)降氖锥税l(fā)出,沿著鏈的路徑一次傳遞拌汇,直到有對象處理這個請求為止,我們將這樣的模式稱為責(zé)任鏈模式噪舀。
責(zé)任鏈模式屬于行為型設(shè)計模式魁淳。

定義

使多個對象都有機(jī)會處理請求,從而避免了請求的發(fā)送者和接受者之間的耦合關(guān)系界逛。將這些對象連成一條鏈,并沿這條鏈傳遞請求息拜,直到有對象處理它為止溉潭。

使用場景

  • 多個對象可以處理同一請求,但具體由哪個對象處理則在運(yùn)行時動態(tài)決定少欺。
  • 在請求處理者不明確的情況下向多個對象中的一個提交一個請求喳瓣。
  • 需要動態(tài)指定一組對象處理請求。

結(jié)構(gòu)

1 簡單版的責(zé)任鏈模式結(jié)構(gòu)

責(zé)任鏈模式 UML 圖 1
  • Handler : 抽象處理者對象狈茉,聲明一個請求處理的方法夫椭,并持有下一個處理節(jié)點 Handler 對象的引用。
  • ConcreteHandler : 具體處理者角色氯庆,對請求進(jìn)行處理蹭秋,不能處理的則將請求傳遞給下一個節(jié)點的處理者。

簡單示例

/**
 * 抽象處理者
 */
public abstract class Handler {

    protected Handler mSuccessor;

    public void setSuccessor(Handler successor) {
        mSuccessor = successor;
    }

    public abstract void handleRequest(String condition);

}
/**
 * 具體的處理者堤撵,ConcreteHandler1
 */
public class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(String condition) {
        if (condition.equals("ConcreteHandler1")) {
            System.out.println("ConcreteHandler1 handled");
        } else {
            mSuccessor.handleRequest(condition);
        }
    }
}
/**
 * 具體的處理者仁讨,ConcreteHandler2
 */
public class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(String condition) {
        if (condition.equals("ConcreteHandler2")) {
            System.out.println("ConcreteHandler2 handled");
        } else {
            mSuccessor.handleRequest(condition);
        }
    }
}
/**
 * 具體的處理者,ConcreteHandler3
 */
public class ConcreteHandler3 extends Handler {
    @Override
    public void handleRequest(String condition) {
        if (condition.equals("ConcreteHandler3")) {
            System.out.println("ConcreteHandler3 handled");
        } else {
            mSuccessor.handleRequest(condition);
        }
    }
}
public class Client {

    public static void main(String args[]) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
        handler1.mSuccessor = handler2;
        handler2.mSuccessor = handler3;
        //處理請求
        handler1.handleRequest("ConcreteHandler3");
    }

}

這里的請求是一個固定的 String 字符串实昨,但是在實際運(yùn)用中洞豁,可能請求的情況會比較復(fù)雜,所以這里的請求也可以抽出一個基類荒给,進(jìn)行封裝丈挟。

2 改進(jìn)的責(zé)任鏈模式結(jié)構(gòu)

責(zé)任鏈模式 UML 圖 2

這里增加了 level ,只有處理者和請求的級別一致時志电,才能處理該請求曙咽,不然就交由下一個節(jié)點的處理者處理該請求。

簡單示例

/**
 * 抽象的請求
 */
public abstract class Request {

    // 需要處理的內(nèi)容
    private Object mContent;

    public Request(Object content) {
        mContent = content;
    }

    public Object getContent() {
        return mContent;
    }

    public abstract int getRequestLevel();
}
/**
 * 請求的具體實現(xiàn)類挑辆,ConcreteRequest1
 */
public class ConcreteRequest1 extends Request {

    public ConcreteRequest1(Object content) {
        super(content);
    }

    @Override
    public int getRequestLevel() {
        return 1;
    }
}
/**
 * 請求的具體實現(xiàn)類例朱,ConcreteRequest2
 */
public class ConcreteRequest2 extends Request {

    public ConcreteRequest2(Object content) {
        super(content);
    }

    @Override
    public int getRequestLevel() {
        return 2;
    }
}
/**
 * 請求的具體實現(xiàn)類,ConcreteRequest3
 */
public class ConcreteRequest3 extends Request {

    public ConcreteRequest3(Object content) {
        super(content);
    }

    @Override
    public int getRequestLevel() {
        return 3;
    }
}
/**
 * 抽象處理者
 */
public abstract class Handler {

    protected Handler mSuccessor;

    public void setSuccessor(Handler successor) {
        mSuccessor = successor;
    }

    public void handleRequest(Request request) {
        if (getHandlerLevel() == request.getRequestLevel()) {
            handle(request);
        } else {
            mSuccessor.handleRequest(request);
        }
    }

    public abstract int getHandlerLevel();

    public abstract void handle(Request request);
}
/**
 * 具體的處理者鱼蝉,ConcreteHandler1
 */
public class ConcreteHandler1 extends Handler {

    @Override
    public int getHandlerLevel() {
        return 1;
    }

    @Override
    public void handle(Request request) {
        System.out.println("ConcreteHandler1 handled");
    }
}
/**
 * 具體的處理者洒嗤,ConcreteHandler2
 */
public class ConcreteHandler2 extends Handler {
    @Override
    public int getHandlerLevel() {
        return 2;
    }

    @Override
    public void handle(Request request) {
        System.out.println("ConcreteHandler2 handled");
    }
}
/**
 * 具體的處理者,ConcreteHandler3
 */
public class ConcreteHandler3 extends Handler {
    @Override
    public int getHandlerLevel() {
        return 3;
    }

    @Override
    public void handle(Request request) {
        System.out.println("ConcreteHandler3 handled");
    }
}
/**
 * Created by linpu on 2019/2/14 .
 */
public class Client {

    public static void main(String args[]) {
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
        handler1.mSuccessor = handler2;
        handler2.mSuccessor = handler3;

        Request request1 = new ConcreteRequest1("Requestq1");
        Request request2 = new ConcreteRequest2("Requestq2");
        Request request3 = new ConcreteRequest3("Requestq3");

        //處理請求
        handler1.handleRequest(request1);
        handler1.handleRequest(request2);
        handler1.handleRequest(request3);
    }

}

實現(xiàn)

XX 需要申請五萬的經(jīng)費魁亦。于是他向他的上級渔隶,也就是項目組的組長提出申請,但是組長沒有權(quán)限審批這么大數(shù)目的經(jīng)費吉挣。于是派撕,組長找到部門主管婉弹,主管一看也超出了自己的權(quán)限。于是繼續(xù)找到上級的經(jīng)理终吼,經(jīng)理看了說他只能審批1萬以內(nèi)的數(shù)額镀赌,所以他拿著審批文件找到了老板。最后老板看了文件后批準(zhǔn)了际跪。
在整個申請過程中,申請人 XX 只和組長產(chǎn)生了關(guān)聯(lián)姆打,然后請求就層層的網(wǎng)上傳達(dá),他不關(guān)心中間的過程玛追,只關(guān)心最后的審批結(jié)果闲延。所以說,責(zé)任鏈很好的將請求的發(fā)起者和處理者進(jìn)行了解耦陆馁。

具體代碼如下:

/**
 * 抽象領(lǐng)導(dǎo)者類
 */
public abstract class Leader {

    protected Leader mAccessor;

    public void handleRequest(int money) {
        if (money <= limit()) {
            handler(money);
        } else {
            if (mAccessor != null) {
                mAccessor.handleRequest(money);
            }
        }
    }

    // 最高能批復(fù)的額度
    public abstract int limit();

    public abstract void handler(int money);
}
/**
 * 組長類
 */
public class GroupLeader extends Leader {
    @Override
    public int limit() {
        return 1000;
    }

    @Override
    public void handler(int money) {
        System.out.println("組長批復(fù)報銷:" + money + " 元");
    }
}
/**
 * 主管類
 */
public class Director extends Leader {
    @Override
    public int limit() {
        return 5000;
    }

    @Override
    public void handler(int money) {
        System.out.println("主管批復(fù)報銷:" + money + " 元");
    }
}
/**
 * 經(jīng)理類
 */
public class Manager extends Leader {
    @Override
    public int limit() {
        return 10000;
    }

    @Override
    public void handler(int money) {
        System.out.println("經(jīng)理批復(fù)報銷:" + money + " 元");
    }
}
/**
 * 老板類
 */
public class Boss extends Leader {
    @Override
    public int limit() {
        return Integer.MAX_VALUE;
    }

    @Override
    public void handler(int money) {
        System.out.println("老板批復(fù)報銷:" + money + " 元");
    }
}
/**
 * 發(fā)起請求的職員
 */
public class Staff {

    public static void main(String args[]) {
        Leader groupLeader = new GroupLeader();
        Leader director = new Director();
        Leader manager = new Manager();
        Leader boss = new Boss();

        groupLeader.mAccessor = director;
        director.mAccessor = manager;
        manager.mAccessor = boss;

        //想組長發(fā)起申請
        groupLeader.handleRequest(50000);
    }

}

結(jié)果:

老板批復(fù)報銷:50000 元

總結(jié)

優(yōu)點:
對請求者和處理者進(jìn)行了解耦叮贩,提高代碼的靈活性佛析。

缺點:
需要對鏈進(jìn)行遍歷,如果處理者很多寸莫,那整個遍歷的時間可能就很長,可能會影響性能。



相關(guān)文章:

設(shè)計模式整理(1) 代理模式
設(shè)計模式整理(2) 單例模式
設(shè)計模式整理(3) Builder 模式
設(shè)計模式整理(4) 原型模式
設(shè)計模式整理(5) 工廠模式
設(shè)計模式整理(6) 策略模式
設(shè)計模式整理(7) 狀態(tài)模式
設(shè)計模式整理(8) 責(zé)任鏈模式
設(shè)計模式整理(9) 觀察者模式
設(shè)計模式整理(10) 適配器模式
設(shè)計模式整理(11) 裝飾模式
設(shè)計模式整理(12) 中介者模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刮萌,隨后出現(xiàn)的幾起案子娘扩,更是在濱河造成了極大的恐慌壮锻,老刑警劉巖涮阔,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掰邢,居然都是意外死亡伟阔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門怀估,熙熙樓的掌柜王于貴愁眉苦臉地迎上來合搅,“玉大人,你說我怎么就攤上這事历筝。” “怎么了麻削?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵春弥,是天一觀的道長。 經(jīng)常有香客問我扫责,道長,這世上最難降的妖魔是什么鳖孤? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任苏揣,我火速辦了婚禮,結(jié)果婚禮上推姻,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好忍燥,可當(dāng)我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布梅垄。 她就那樣靜靜地躺著,像睡著了一般哎甲。 火紅的嫁衣襯著肌膚如雪饲嗽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天吞加,我揣著相機(jī)與錄音,去河邊找鬼衔憨。 笑死袄膏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沉馆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼斥黑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兽狭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤箕慧,失蹤者是張志新(化名)和其女友劉穎销钝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡婉商,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丈秩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡饺著,死狀恐怖肠牲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缀雳,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布识椰,位于F島的核電站深碱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏敷硅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一竞膳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坦辟,春花似錦、人聲如沸滨彻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梁厉。三九已至踏兜,卻和暖如春八秃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背昔驱。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留骤肛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓繁成,卻偏偏與公主長得像秕豫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子混移,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,512評論 2 359