一辈毯、概念
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