設(shè)計(jì)模式專(zhuān)題-責(zé)任鏈設(shè)計(jì)模式

責(zé)任鏈設(shè)計(jì)模式的場(chǎng)景


問(wèn)題
? ? ? ?這里我們以一個(gè)機(jī)器師傅為例子蟹漓,每個(gè)師傅他的經(jīng)驗(yàn)技能都是不一樣的索抓,有些人比較熟練碳蛋,有些人比較生手胚泌,那么我們?cè)趺幢WC,當(dāng)訂單來(lái)了的時(shí)候肃弟,找到最合適師傅去處理這個(gè)任務(wù)呢玷室?此時(shí)零蓉,可以使用責(zé)任鏈設(shè)計(jì)模式

解決方案
? ? ? ?我們把所有的工程師分為四種不同的等級(jí):只是加油的穷缤、初級(jí)敌蜂、學(xué)徒和熟練的工程師。每個(gè)人都有屬于自己的技能等級(jí)的標(biāo)志津肛,相同等級(jí)的人歸為一個(gè)組章喉,每一個(gè)組都有可能有更高級(jí)別的技能組存在(當(dāng)然,如果是最高技能的那個(gè)組身坐,那就沒(méi)有更高級(jí)別的組了)秸脱。這樣子分配之后,我們模擬在一個(gè)店里面部蛇,現(xiàn)在有一個(gè)任務(wù)摊唇,那么,我們應(yīng)該如何執(zhí)行呢涯鲁?按照責(zé)任鏈設(shè)計(jì)模式巷查,應(yīng)該先找最低級(jí)別的技能組,尋找是否有人能夠解決撮竿,如果不能吮便,繼續(xù)網(wǎng)下一個(gè)級(jí)別尋找,直到找到人去處理任務(wù)幢踏,或者認(rèn)為店里面已經(jīng)沒(méi)人能夠處理任務(wù)了髓需。

好,基本情況介紹到這里房蝉,下面進(jìn)行代碼拆解僚匆。。搭幻。咧擂。。
這是一條完美的分割線(xiàn)


首先我們定義一個(gè)技能表

/// 技能表
///
/// - OilChangeOnly: 只是加油的
/// - junior: 初級(jí)
/// - Apprentice: 學(xué)徒
/// - MasterMechanic: 熟練
enum Skill: Int {
    case OilChangeOnly = 1, junior, Apprentice, MasterMechanic
}

接下來(lái)檀蹋,我們定義一個(gè)工作類(lèi),工作類(lèi)里面包含了需要的技能松申、工作名稱(chēng)和是否完成等屬性。

/// 工作
class Job {
    let minimumSkillSet: Skill
    let name: String
    var completed: Bool = false
    
    init(minimumSkillSet: Skill, name: String) {
        
        self.minimumSkillSet = minimumSkillSet
        self.name = name
    }
}

有了工作俯逾,怎么能少得了干活的機(jī)器呢贸桶?同樣的,這個(gè)機(jī)器擁有技能桌肴、名稱(chēng)和是否在忙等屬性皇筛,并且他有一個(gè)去執(zhí)行工作的方法,具體坠七,請(qǐng)看代碼.....

class Mechanic {
    
    let skill: Skill
    var name: String
    var isBusy: Bool = false
    
    init(skill: Skill, name: String) {
        
        self.skill = skill
        self.name = name
    }
    
    func performJob(job: Job) -> Bool {
        
        //該技能不在此機(jī)器的工作范圍或者該機(jī)器在忙
        if job.minimumSkillSet.rawValue > self.skill.rawValue || isBusy == true {
            
            assert(false, "This mechanic is either busy or insufficiently skilled for this job, he should have never been asked to perform it, there is something wrong in the chain of responsibility")
        }else {
            
            isBusy = true
            print("\(name) with skill set \(skill) has started to do \(job.name)")
            job.completed = true
            return true
        }
        
    }
}

為了將擁有同樣技能的機(jī)器分類(lèi)水醋,我們?cè)俣x一個(gè)叫機(jī)器組的類(lèi)旗笔,讓他來(lái)管理所有擁有相同技能的機(jī)器。功能拄踪,看代碼你就懂了蝇恶,哈哈

class MechanicSkillGroup {
    
    var mechanics: [Mechanic]
    var nextLevel: MechanicSkillGroup?
    var skill: Skill
    
    init(skill: Skill, mechanics: [Mechanic], nextLevel: MechanicSkillGroup?) {
        
        self.mechanics = mechanics
        self.skill = skill
        self.nextLevel = nextLevel
    }
    
    func performJobOrPassItUp(job: Job) -> Bool {

        //當(dāng)前工作組的機(jī)器無(wú)法滿(mǎn)足功能
        if job.minimumSkillSet.rawValue > skill.rawValue || mechanics.filter({$0.isBusy == false}).count == 0{
            //尋找下一個(gè)機(jī)器組工作
            if let nextLevel = nextLevel {
                
                return nextLevel.performJobOrPassItUp(job: job)
                
            }else {
                
                print("No one is aavailable to do this job")
                return false
            }
            
        }else {
            //不忙又滿(mǎn)足技能要求的,隨便找一個(gè)工作就可以了
            if let firstAvailavbleMechanic = mechanics.filter({$0.isBusy == false}).first {
                
                return firstAvailavbleMechanic.performJob(job: job)
            }
            assert(false, "This should never be reached since our if-else statment is fully exhaustive. You cannot have both all mechanics busy and an available mechanic within one skill group")
        }
    }
}

最后惶桐,我們模擬一個(gè)商店類(lèi):

class Shop {
    
    private var firstMechanics: MechanicSkillGroup
    
    init(firstMechanics: MechanicSkillGroup) {
        
        self.firstMechanics = firstMechanics
    }
    
    @discardableResult
    func performJob(job: Job) -> Bool {
        
        return firstMechanics.performJobOrPassItUp(job: job)
    }
}

好了艘包,基本的準(zhǔn)備,我們都有了耀盗,下面我們來(lái)測(cè)試一下:

func chainOfResponsibilityTestFunction() {
    
    
    /// 獲得熟練的工程師
    ///
    /// - Returns: 熟練的工程師
    func masterMechanics() -> MechanicSkillGroup {

        let steve = Mechanic(skill: .MasterMechanic, name: "Steve Frank")
        let joe = Mechanic(skill: .MasterMechanic, name: "Joe Alison")
        let jack = Mechanic(skill: .MasterMechanic, name: "Jack Ryan")
        let brian = Mechanic(skill: .MasterMechanic, name: "Drake Jin")
        
        return MechanicSkillGroup(skill: .MasterMechanic, mechanics: [steve, joe, jack, brian], nextLevel: nil)
    }
    
    /// 獲得學(xué)徒工程師
    ///
    /// - Returns: 學(xué)徒工程師
    func apprenticeMechanics() -> MechanicSkillGroup {
        
        let tyson = Mechanic(skill: .Apprentice, name: "Tyson Trup")
        let tina = Mechanic(skill: .Apprentice, name: "Tina Bernard")
        let bryan = Mechanic(skill: .Apprentice, name: "Bryan Tram")
        let lin = Mechanic(skill: .Apprentice, name: "Lin Young")

        return MechanicSkillGroup(skill: .Apprentice, mechanics: [tyson, tina, bryan, lin], nextLevel: masterMechanics())
    }
    
    /// 獲得初級(jí)工程師
    ///
    /// - Returns: 初級(jí)工程師
    func juniorMechanics() -> MechanicSkillGroup {
        
        let ken = Mechanic(skill: .junior, name: "ken Hudson")
        let matt = Mechanic(skill: .junior, name: "Matt Lowes")
        let sandeep = Mechanic(skill: .junior, name: "Sandeep Shenoy")
        let tom = Mechanic(skill: .junior, name: "Tom Berry")
        
        return MechanicSkillGroup(skill: .junior, mechanics: [ken, matt, sandeep, tom], nextLevel: apprenticeMechanics())
    }
    
    /// 獲得只有石油改變工程師
    ///
    /// - Returns: 只有石油改變工程師
    func oilChangeOnlyesMechanics() -> MechanicSkillGroup {
     
        let grant = Mechanic(skill: .OilChangeOnly, name: "Grant Hughes")
        
        return MechanicSkillGroup(skill: .OilChangeOnly, mechanics: [grant], nextLevel: juniorMechanics())
    }
    
    //建造虛擬商店
    let shop = Shop(firstMechanics: oilChangeOnlyesMechanics())

    let jobs = [Job(minimumSkillSet: .junior, name: "Windshield Wiper"),
                Job(minimumSkillSet: .Apprentice, name: "Light Bulb Change"),
                Job(minimumSkillSet: .Apprentice, name: "Battery Replacement"),
                Job(minimumSkillSet: .OilChangeOnly, name: "General Oil Change"),
                Job(minimumSkillSet: .OilChangeOnly, name: "General Oil Change"),
                Job(minimumSkillSet: .OilChangeOnly, name: "General Oil Change"),
                Job(minimumSkillSet: .OilChangeOnly, name: "General Oil Change"),
                Job(minimumSkillSet: .MasterMechanic, name: "Timing Belt Replacement"),
                Job(minimumSkillSet: .junior, name: "Brake Pads Replacement")]
    
    for job in jobs {
        
        shop.performJob(job: job)
    }
    
}

下面我們來(lái)看看打印信息:


image.png

所有的工作,都有序的進(jìn)行卦尊,但你會(huì)發(fā)現(xiàn)叛拷,一些加油這種小事情,有可能讓擁有junior技能的機(jī)器去干活岂却,這正是責(zé)任鏈設(shè)計(jì)模式特點(diǎn)忿薇,他是可以很好的分配你的工作資源,更合理的利用你的資源躏哩,在初級(jí)都在忙的情況下署浩,他會(huì)去找更高級(jí)的人去干活,而不是讓更高級(jí)的人閑著扫尺。

好了筋栋,責(zé)任鏈設(shè)計(jì)模式就介紹到這里吧,有疑問(wèn)的歡迎咨詢(xún)......
對(duì)了正驻,如果你喜歡看英文弊攘,歡迎點(diǎn)開(kāi)這個(gè)鏈接英文原文

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市姑曙,隨后出現(xiàn)的幾起案子襟交,更是在濱河造成了極大的恐慌,老刑警劉巖伤靠,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捣域,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宴合,警方通過(guò)查閱死者的電腦和手機(jī)焕梅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)形纺,“玉大人丘侠,你說(shuō)我怎么就攤上這事≈鹧” “怎么了蜗字?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵打肝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我挪捕,道長(zhǎng)粗梭,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任级零,我火速辦了婚禮断医,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奏纪。我一直安慰自己鉴嗤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布序调。 她就那樣靜靜地躺著醉锅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪发绢。 梳的紋絲不亂的頭發(fā)上硬耍,一...
    開(kāi)封第一講書(shū)人閱讀 49,798評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音边酒,去河邊找鬼经柴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛墩朦,可吹牛的內(nèi)容都是我干的坯认。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼介杆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鹃操!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起春哨,我...
    開(kāi)封第一講書(shū)人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荆隘,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后赴背,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體椰拒,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年凰荚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燃观。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡便瑟,死狀恐怖缆毁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情到涂,我是刑警寧澤脊框,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布颁督,位于F島的核電站,受9級(jí)特大地震影響浇雹,放射性物質(zhì)發(fā)生泄漏沉御。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一昭灵、第九天 我趴在偏房一處隱蔽的房頂上張望吠裆。 院中可真熱鬧,春花似錦烂完、人聲如沸试疙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)效斑。三九已至,卻和暖如春柱徙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奇昙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工护侮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人储耐。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓羊初,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親什湘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子长赞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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

  • 書(shū)名貪婪的大腦:為何人類(lèi)會(huì)無(wú)止境地尋求意義作者(英)丹尼爾·博爾(Daniel Bor)譯者林旭文豆瓣http:/...
    xuwensheng閱讀 15,205評(píng)論 8 54
  • 梁梁2017年10月9日日記 今天早上6點(diǎn)26起床,是早起的第39天闽撤,感謝上天給我的每一天的時(shí)間得哆,在房...
    梁志昌總裁閱讀 229評(píng)論 0 1
  • 做飯是個(gè)拋物線(xiàn) 為什么這么說(shuō) 你想啊 商量想吃什么的時(shí)候 興致吱嘎吱嘎的一格格攀升 殺到菜市場(chǎng)的時(shí)候 看著脆生生的...
    驕傲的樹(shù)閱讀 251評(píng)論 0 0
  • 雨天的時(shí)候, 我總會(huì)貪戀時(shí)空哟旗, 那秋日的午后贩据, 閑適,寂然闸餐。 你忙碌著花草饱亮, 經(jīng)營(yíng)著日子, 整理著心情舍沙, 就如花開(kāi)...
    夏兒的夏閱讀 436評(píng)論 18 8