iOS 設計模式之十四(職責鏈模式)

一辈毯、概念

1坝疼、職責鏈模式的動機

? 企業(yè)的采購審批是分級進行的,即根據(jù)采購金額的不同由不同層次的主管人員來審批谆沃。比如主管可以審批5千以下的钝凶,經(jīng)理可以審批2萬以下的,總經(jīng)理可以審批10萬以下的唁影,超過10萬的需要上報董事會耕陷。

? 在設計模式中,我們也有一種專門用于處理這種請求鏈式傳遞的模式据沈,它就是職責鏈模式哟沫。

2、職責鏈模式的定義

? 職責鏈模式(Chain of Responsibility Pattern):避免請求發(fā)送者與接收者耦合在一起锌介,讓多個對象都有可能接收請求嗜诀,將這些對象連接成一條鏈,并且沿著這條鏈傳遞請求孔祸,直到有對象處理它為止隆敢。職責鏈模式是一種對象行為型模式。

3崔慧、職責鏈模式的2個角色

1)Handler(抽象處理者):它定義了一個處理請求的接口筑公,一般設計為抽象類,由于不同的具體處理者處理請求的方式不同尊浪,因此在其中定義了抽象請求處理方法匣屡。因為每一個處理者的下家還是一個處理者封救,因此在抽象處理者中定義了一個抽象處理者類型的對象(如結構圖中的successor),作為其對下家的引用捣作。通過該引用誉结,處理者可以連成一條鏈。
2)ConcreteHandler(具體處理者):它是抽象處理者的子類券躁,可以處理用戶請求惩坑,在具體處理者類中實現(xiàn)了抽象處理者中定義的抽象請求處理方法,在處理請求之前需要進行判斷也拜,看是否有相應的處理權限以舒,如果可以處理請求就處理它,否則將請求轉發(fā)給后繼者慢哈;在具體處理者中可以訪問鏈中下一個對象浑吟,以便請求的轉發(fā)腿倚。

? 在職責鏈模式里扮宠,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈懂缕。

4、結構圖
職責鏈模式

二键俱、示例

? 職責鏈模式的核心在于抽象處理者類的設計兰绣。具體處理者是抽象處理者的子類,它具有兩大作用:第一是處理請求编振;第二是轉發(fā)請求缀辩。

1)先創(chuàng)建一個PurchaseRequest采購單類,表示Request踪央;

2)然后創(chuàng)建Leader類臀玄,類中有一個successor屬性,還有處理request的方法杯瞻,表示抽象處理者;

3)最后創(chuàng)建三個類TeamLeader炫掐、DeparmentManager和CTO魁莉,都繼承自Leader類,表示具體處理者募胃。

PurchaseRequest類:

// 采購單
@interface PurchaseRequest : NSObject
@property (nonatomic, assign) float price;
@property (nonatomic, copy) NSString *purpose;
- (instancetype)initWithPrice:(float)price purpose:(NSString *)purpose;
@end

@implementation PurchaseRequest
- (instancetype)initWithPrice:(float)price purpose:(NSString *)purpose {
    self = [super init];
    if (self) {
        _price = price;
        _purpose = purpose;
    }
    return self;
}
@end

Leader類:

// 抽象類
@interface Leader : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) Leader *successor; //繼任者
- (instancetype)initWithName:(NSString *)name;
- (void)handleRequest:(PurchaseRequest *)request;
@end

@implementation Leader
- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

- (void)handleRequest:(PurchaseRequest *)request {}
@end

TeamLeader旗唁、DeparmentManager和CTO類:

// TeamLeader
@interface TeamLeader : Leader

@end
@implementation TeamLeader
- (void)handleRequest:(PurchaseRequest *)request {
    if (request.price < 200) { // 處理請求
        NSLog(@"審批組長:%@, 金額:%.2f, 目的:%@", self.name, request.price, request.purpose);
    } else { // 轉發(fā)請求
        [self.successor handleRequest:request];
    }
}
@end

// DeparmentManager
@interface DeparmentManager : Leader

@end
@implementation DeparmentManager
- (void)handleRequest:(PurchaseRequest *)request {
    if (request.price < 2000) {
        NSLog(@"審批部門經(jīng)理:%@, 金額:%.2f, 目的:%@", self.name, request.price, request.purpose);
    } else {
        [self.successor handleRequest:request];
    }
}
@end

// CTO
@interface CTO : Leader

@end
@implementation CTO
- (void)handleRequest:(PurchaseRequest *)request {
    if (request.price < 20000) {
        NSLog(@"審批技術總監(jiān):%@, 金額:%.2f, 目的:%@", self.name, request.price, request.purpose);
    } else {
        NSLog(@"金額%.2f超過預算,不能%@", request.price, request.purpose);
    }
}
@end

運行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 創(chuàng)建對象
    Leader *teamLeader, *manager, *cto;
    teamLeader = [[TeamLeader alloc] initWithName:@"張三"];
    manager = [[DeparmentManager alloc] initWithName:@"李四"];
    cto = [[CTO alloc] initWithName:@"王五"];
    
    // 創(chuàng)建職責鏈
    teamLeader.successor = manager;
    manager.successor = cto;
    
    // 創(chuàng)建采購單
    PurchaseRequest *taxi = [[PurchaseRequest alloc] initWithPrice:60 purpose:@"加班太晚痹束,需要打車"];
    [teamLeader handleRequest:taxi];
    
    PurchaseRequest *iphone = [[PurchaseRequest alloc] initWithPrice:1500 purpose:@"購買測試機"];
    [teamLeader handleRequest:iphone];
    
    PurchaseRequest *mac = [[PurchaseRequest alloc] initWithPrice:16000 purpose:@"購買蘋果電腦"];
    [teamLeader handleRequest:mac];
    
    PurchaseRequest *diamond = [[PurchaseRequest alloc] initWithPrice:80000 purpose:@"購買鉆石"];
    [teamLeader handleRequest:diamond];
}

打印結果:

審批組長:張三, 金額:60.00, 目的:加班太晚检疫,需要打車
審批部門經(jīng)理:李四, 金額:1500.00, 目的:購買測試機
審批技術總監(jiān):王五, 金額:16000.00, 目的:購買蘋果電腦
金額80000.00超過預算,不能購買鉆石

三祷嘶、總結

? 職責鏈模式通過建立一條鏈來組織請求的處理者屎媳,請求將沿著鏈進行傳遞夺溢,請求發(fā)送者無須知道請求在何時、何處以及如何被處理烛谊,實現(xiàn)了請求發(fā)送者與處理者的解耦风响。在軟件開發(fā)中,如果遇到有多個對象可以處理同一請求時可以應用職責鏈模式丹禀。

1状勤、優(yōu)點

1、職責鏈模式使得一個對象無須知道是其他哪一個對象處理其請求双泪,對象僅需知道該請求會被處理即可持搜,接收者和發(fā)送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結構焙矛,由客戶端負責鏈的創(chuàng)建葫盼,降低了系統(tǒng)的耦合度。

2薄扁、請求處理對象僅需維持一個指向其后繼者的引用剪返,而不需要維持它對所有的候選處理者的引用,可簡化對象的相互連接邓梅。

3脱盲、在給對象分派職責時,職責鏈可以給我們更多的靈活性日缨,可以通過在運行時對該鏈進行動態(tài)的增加或修改來增加或改變處理一個請求的職責钱反。

4、 在系統(tǒng)中增加一個新的具體請求處理者時無須修改原有系統(tǒng)的代碼匣距,只需要在客戶端重新建鏈即可面哥,從這一點來看是符合“開閉原則”的。

2毅待、缺點

1尚卫、由于一個請求沒有明確的接收者,那么就不能保證它一定會被處理尸红,該請求可能一直到鏈的末端都得不到處理吱涉;一個請求也可能因職責鏈沒有被正確配置而得不到處理。

2外里、對于比較長的職責鏈怎爵,請求的處理可能涉及到多個處理對象,系統(tǒng)性能將受到一定影響盅蝗,而且在進行代碼調試時不太方便鳖链。

3、如果建鏈不當墩莫,可能會造成循環(huán)調用芙委,將導致系統(tǒng)陷入死循環(huán)逞敷。

3、適用場景

1题山、有多個對象可以處理同一個請求兰粉,具體哪個對象處理該請求待運行時刻再確定,客戶端只需將請求提交到鏈上顶瞳,而無須關心請求的處理對象是誰以及它是如何處理的玖姑。

2、在不明確指定接收者的情況下慨菱,向多個對象中的一個提交一個請求焰络。

3、可動態(tài)指定一組對象處理請求符喝,客戶端可以動態(tài)創(chuàng)建職責鏈來處理請求闪彼,還可以改變鏈中處理者之間的先后次序。

4协饲、iOS應用舉例

? iOS事件的傳遞和響應就是職責鏈模式的實現(xiàn)畏腕。

Demo地址:iOS-Design-Patterns

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茉稠,隨后出現(xiàn)的幾起案子描馅,更是在濱河造成了極大的恐慌,老刑警劉巖而线,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铭污,死亡現(xiàn)場離奇詭異,居然都是意外死亡膀篮,警方通過查閱死者的電腦和手機嘹狞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來誓竿,“玉大人磅网,你說我怎么就攤上這事】曷牛” “怎么了涧偷?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長速蕊。 經(jīng)常有香客問我嫂丙,道長娘赴,這世上最難降的妖魔是什么规哲? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮诽表,結果婚禮上唉锌,老公的妹妹穿的比我還像新娘隅肥。我一直安慰自己,他們只是感情好袄简,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布腥放。 她就那樣靜靜地躺著,像睡著了一般绿语。 火紅的嫁衣襯著肌膚如雪秃症。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天吕粹,我揣著相機與錄音种柑,去河邊找鬼。 笑死匹耕,一個胖子當著我的面吹牛聚请,可吹牛的內容都是我干的。 我是一名探鬼主播稳其,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼驶赏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了既鞠?” 一聲冷哼從身側響起煤傍,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎损趋,沒想到半個月后患久,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡浑槽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年蒋失,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桐玻。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡篙挽,死狀恐怖,靈堂內的尸體忽然破棺而出镊靴,到底是詐尸還是另有隱情铣卡,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布偏竟,位于F島的核電站煮落,受9級特大地震影響,放射性物質發(fā)生泄漏踊谋。R本人自食惡果不足惜蝉仇,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧轿衔,春花似錦沉迹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宛官,卻和暖如春葫松,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背底洗。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工进宝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枷恕。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓党晋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親徐块。 傳聞我的和親對象是個殘疾皇子未玻,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內容