學(xué)好設(shè)計模式防被祭天:責(zé)任鏈模式

責(zé)任鏈模式

為了防止被“殺”了祭天,學(xué)點設(shè)計模式,并總結(jié)下還是有必要的。

一:理解

  1. 在責(zé)任鏈模式中,對象通過對另一個對象的引用而連接形成一條鏈。調(diào)用方的請求可以在鏈上傳遞,直到找到滿足要求的處理對象,或者走完整個鏈。
  2. 責(zé)任鏈將調(diào)用方和服務(wù)方進(jìn)行解耦,調(diào)用方無需知道服務(wù)方內(nèi)部的邏輯。
  3. Tomcat的過濾器鏈FilterChain中使用了責(zé)任鏈模式。


二:例子

你是個富二代。

你爸給了你5個億讓你玩投資。

雖然你貴為富二代,不過一下子給你5個億,你還是略略有點觸不及防的。

于是,你開始滿世界的招管理人員輔助你投資,準(zhǔn)備大干一番。

準(zhǔn)備大干一番

你還叫來了程序員小菜幫你抽象一下投資工資的員工管理問題。

小菜上來就是一頓敲。

為了對員工的行為進(jìn)行約束,他首先新建了一個抽象經(jīng)理類Manager。

Manager類中只有一個方法handleInvestment,即處理投資。

@Data
public abstract class Manager {
    public abstract void handleInvestment(long amount);
}

接著,小菜新建了不同級別的經(jīng)理,有一級,二級,三級管理人員,當(dāng)然你是最高級別的經(jīng)理。

他們都繼承自Manager抽象類。他們處理投資的方法各不一樣,為了方便舉例,只輸出一句話。

// 一級經(jīng)理
public class AManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        System.out.println("一級已經(jīng)處理");
    }
}

// 二級經(jīng)理
public class BManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        System.out.println("二級經(jīng)理已經(jīng)處理");
    }
}

// 三級經(jīng)理
public class CManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        System.out.println("三級經(jīng)理已經(jīng)處理");
    }
}

// 你,最高級經(jīng)理
public class You extends Manager {
    @Override
    public void handleInvestment(long amount) {
        System.out.println("廠長親自處理");
    }
}

作為一個大公司,你不希望所有的投資都直接找你談,你只談大項目,于是你規(guī)定:

  1. 投資金額小于等于一萬元,一級經(jīng)理直接處理。
  2. 投資金額在一萬元到十萬元之間,二級經(jīng)理直接處理。
  3. 投資金額在十萬元到一百萬元之間,三級經(jīng)理直接處理。
  4. 投資金額超過一百萬元,你親自處理。

于是,小菜寫了以下的測試代碼:

public class Client {
    public static void main(String[] args) {
        Manager aManager = new AManager();
        Manager bManager = new BManager();
        Manager cManager = new CManager();
        Manager you = new You();
        int amount = 99999;
        if (amount <= 10000) {
            aManager.handleInvestment(amount);
        } else if (amount <= 100000) {
            bManager.handleInvestment(amount);
        } else if (amount <= 1000000) {
            cManager.handleInvestment(amount);
        } else {
            you.handleInvestment(amount);
        }
    }
}

輸入/輸出:

二級經(jīng)理已經(jīng)處理

投資公司順利地開起來了,你也很開心。

一段時間之后,創(chuàng)業(yè)者們紛紛反映很難可以找到對接的經(jīng)理。

因為創(chuàng)業(yè)者需要根據(jù)自己項目所需的金額,找到對應(yīng)的投資人。

創(chuàng)業(yè)者在發(fā)起請求之前,需要在一堆if else中找到符合要求的經(jīng)理。

作為高富帥,你覺得讓投資者自己了解整個游戲規(guī)則,并且徜徉在if else的海洋里,翻過山和大海才能得到投資,很符合你高貴的身份。

然而,畢竟是第一次開公司,你還是決定讓創(chuàng)業(yè)者們更方便一些。

你決定對公司做出調(diào)整,有以下兩個方案:

  1. 專門設(shè)立一個咨詢類接受投資者的請求,咨詢類根據(jù)投資金額,將投資請求提交到對應(yīng)的經(jīng)理。
  2. 所有投資直接找一級經(jīng)理。如果一級經(jīng)理無權(quán)處理,往上申請,直到向你申請為止。

小菜驚訝于你竟然會產(chǎn)生這樣的想法,表示book思議。

book思議

然而在你的淫威下,小菜開始重構(gòu)代碼。

小菜認(rèn)為,方案一需要多招至少一名員工,你那么大方,是肯定不會同意的。

于是,他決定嘗試使用責(zé)任鏈模式來重構(gòu)這個程序。

因為不同等級的經(jīng)理有關(guān)聯(lián)關(guān)系,并且調(diào)用呈鏈?zhǔn)疥P(guān)系,即一級到二級,二級到更上級,直到最上級。

小菜首先抽象出Manager類,Manager中有一個superior屬性,該屬性表示的是當(dāng)前對象的上級。

superior也屬于Manager類,因為經(jīng)理的上級仍舊是一個經(jīng)理。

@Data
public abstract class Manager {
    private Manager superior;

    public abstract void handleInvestment(long amount);
}

接著,小菜新建了一級經(jīng)理,二級經(jīng)理,三級經(jīng)理和你對應(yīng)的類。

// 一級經(jīng)理
public class AManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        if (amount <= 10000) {
            System.out.println("一級經(jīng)理已經(jīng)處理");
            return;
        }
        getSuperior().handleInvestment(amount);
    }
}

// 二級經(jīng)理
public class BManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        if (amount <= 100000) {
            System.out.println("二級經(jīng)理已經(jīng)處理");
            return;
        }
        getSuperior().handleInvestment(amount);
    }
}

// 三級經(jīng)理
public class CManager extends Manager {
    @Override
    public void handleInvestment(long amount) {
        if (amount <= 1000000) {
            System.out.println("三級經(jīng)理已經(jīng)處理");
            return;
        }
        getSuperior().handleInvestment(amount);
    }
}

// 你,最高級經(jīng)理
public class You extends Manager {
    @Override
    public void handleInvestment(long amount) {
        System.out.println("廠長親自處理");
    }
}

和之前不同的是,當(dāng)經(jīng)理受到投資請求時,如果投資金額處于自己可處理范圍內(nèi),則直接處理,return。

如果無權(quán)處理,則提交上級進(jìn)行處理。

小菜寫了一段測試代碼:

public class Client {
    public static void main(String[] args) {
        Manager aManager = new AManager();
        Manager bManager = new BManager();
        Manager cManager = new CManager();
        Manager you = new You();
        aManager.setSuperior(bManager);
        bManager.setSuperior(cManager);
        cManager.setSuperior(you);
        aManager.handleInvestment(9999);
        aManager.handleInvestment(99999);
        aManager.handleInvestment(999999);
        aManager.handleInvestment(9999999);
    }
}

輸入/輸出:

一級經(jīng)理已經(jīng)處理
二級經(jīng)理已經(jīng)處理
三級經(jīng)理已經(jīng)處理
廠長親自處理

在經(jīng)過責(zé)任鏈模式重構(gòu)之后,整個投資過程變得很清晰,創(chuàng)業(yè)者無需再了解你司內(nèi)部的邏輯,專心創(chuàng)業(yè)即可。

在例子中,責(zé)任鏈?zhǔn)菃蜗虻模磸南峦稀?/p>

也可以構(gòu)建雙向責(zé)任鏈模式,請求者可以把請求發(fā)到鏈上的任意對象,再根據(jù)是否滿足條件開始在鏈上傳遞。

小菜將重構(gòu)后的代碼給你看,你很開心。

當(dāng)你得知這個模式叫責(zé)任鏈模式之后,你頓時覺得自己的投資公司非常有責(zé)任。

小菜也體驗了一把有bear來的感覺。


有bear來


三:再理解

  1. 例子中通過在類中加入對上級的引用來構(gòu)建調(diào)用鏈,其實也可以用額外的數(shù)據(jù)結(jié)構(gòu)來保存這條鏈。事實上,Tomcat的FilterChain就用額外的數(shù)組來保存的。
  2. 責(zé)任鏈模式簡化了很多if else邏輯,在需要擴展的時候,只需在鏈上加入新對象即可。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內(nèi)容

  • 1 場景問題# 1.1 申請聚餐費用## 來考慮這樣一個功能:申請聚餐費用的管理。 很多公司都有這樣的福利,就是項...
    七寸知架構(gòu)閱讀 3,167評論 3 58
  • 源碼地址 介紹 它是一種行為型設(shè)計模式之一。它的每一個節(jié)點都可以看作是一個對象,每一個對象擁有不同的處理邏輯,將一...
    yangMr閱讀 743評論 0 3
  • 2017.9.17 星期日 星期日 下午,送兒子學(xué)乒乓球路上,電動車線路出了故障,在給好友和老公都打過電話...
    暖與希望閱讀 146評論 0 0
  • 前兩天思遙在群里分享了篇知乎的文章"你和你的室友之間有哪些可以分享的故事?"我忙著上班沒功夫搭理她。今天蹲廁所的時...
    菠蘿吃我閱讀 1,227評論 4 1
  • 百度里對知識是這樣定義的 知識是符合文明方向的,人類對物質(zhì)世界以及精神世界探索的結(jié)果總和。知識,至今也沒有一個統(tǒng)一...
    林山水閱讀 481評論 0 1