定義
為了避免請求寄件者與接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象串連成一條鏈,並且沿著這條鏈傳遞請求,直到有對象處理它為止,職責鏈模式又稱為責任鏈模式,它是一種對象行為型模式。(如果你接觸過異常處理,那麼套用異常處理機制可以更好地理解)。
職責鏈可以是一條直線,也可以是一個環,還可以是一個樹形結構,不過最常見的職責鏈是直線型,即沿著一條單向的鏈來傳遞請求。鏈上的每一個對象都是請求處理者,職責鏈模式可以將請求的處理者組織成一條鏈,並使請求沿著鏈傳遞,由鏈上的處理者對請求進行相應的處理,而用戶端無須關心請求的處理細節以及請求的傳遞,只需將請求發送到鏈上即可,通過這種方法將請求的寄件者和請求的處理者解耦,消除兩個角色間的依賴關係,可以自由地組合。
原理結構
上圖闡釋的是職責連模式的實現原理,主要角色包括:
Handler:抽象處理者。定義出一個處理請求的介面。如果需要,介面可以定義出一個方法,以設定和返回對下家的引用。這個角色通常由一個抽象類別或介面實現。
ConcreteHandler: 具體處理者。具體處理者接到請求後,可以選擇將請求處理掉,或者將請求傳給下家。由於具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
Client:用戶端
handleRequest:抽象處理者的公用介面,要求每個鏈式節點都實現這個介面,能夠處理用戶端發過來的請求資料。
對於每個鏈式節點,需要滿足一下兩個條件:
實現抽象處理者(Handler)所定義的抽象介面,能夠識別接收的請求;
有一個successor,用於把當前不能處理的請求轉寄傳遞到下一個節點,如此才能形成一個鏈。(successor是指下一個ConcreteHandler的引用,相當於鏈表裡面的next指標)
由於通過上述的編程設計,使得請求和處理該請求的對象完全沒有依賴關係,因為用戶端甚至不知道是誰處理了這個請求,這樣的話,使得整個鏈式結構很靈活,可以隨時添加新的的節點,當然也支援隨意調節節點順序、刪除不必要的節點等等操作。
iOS實現
職責鏈模式的一個很重要的特點是,當客戶發出請求之後,用戶端並不知道哪一個對象最終處理這個請求,這樣系統的更改可以在不影響用戶端的情況下動態地重新組織和分配責任。
下面給出類結構圖。
從上圖可以看出,當客戶提交一個請求時,請求是沿鏈傳遞直至有一個ConcreteHandler對象負責處理它。這樣做的好處是要求者不用管哪個對象來處理,反正最終是要被某一個對象處理就是了。也就是說接收者和寄件者都沒有對方的明確資訊,且鏈中的對象自己也不知道鏈的結構。結果是職責鏈可簡化對象的相互串連,它們僅需保持一個指向其後繼者的引用,而不需保持它所有的候選接受者的引用。
這些特點的好處是我們可以隨時增加或修改處理一個請求的結構。增強了給對象指派職責的靈活性。但是,一個請求極有可能到了鏈的末端都得不到處理,或者因為沒有正確配置而得不到處理,所以這更需要我們事先考慮全面。
好的,說了這麼多,還是老樣子,給大家展示一下簡單的示意代碼。
注意:本文所有代碼均在ARC環境下編譯通過。
Handlers類介面
複製代碼 代碼如下:
#import <Foundation/Foundation.h>
@interface Handlers :NSObject{
Handlers *mySuccessor;
}
-(void)SetSuccessor:(Handlers*)successor;
-(void)HandleRequest:(int)request;
@end
Handlers類實現
複製代碼 代碼如下:
#import "Handlers.h"
@implementation Handlers
-(void)SetSuccessor:(Handlers *)successor{
mySuccessor = successor;
}
-(void)HandleRequest:(int)request{
return;
}
@end
ConcreteHandler1類介面
複製代碼 代碼如下:
#import "Handlers.h"
@interface ConcreteHandler1:Handlers
-(void)HandleRequest:(int)request;
@end
ConcreteHandler1類實現
#import "ConcreteHandler1.h"
@implementation ConcreteHandler1
-(void)HandleRequest:(int)request{
if (request >=0 && request <10) {
NSLog(@"ConcreteHandler1處理%d", request);
}
else if (mySuccessor !=nil) {
[mySuccessor HandleRequest:request];
}
}
@end
ConcreteHandler2類介面
複製代碼 代碼如下:
#import "Handlers.h"
@interface ConcreteHandler2 :Handlers
@end
ConcreteHandler2類實現
複製代碼 代碼如下:
#import "ConcreteHandler2.h"
@implementation ConcreteHandler2
-(void)HandleRequest:(int)request{
if (request >=10 && request <20) {
NSLog(@"ConcreteHandler2處理%d", request);
}
else if(mySuccessor !=nil) {
[mySuccessor HandleRequest:request];
}
}
@end
ConcreteHandler3類介面
複製代碼 代碼如下:
#import "Handlers.h"
@interface ConcreteHandler3 :Handlers
@end
ConcreteHandler3類實現
複製代碼 代碼如下:
#import "ConcreteHandler3.h"
@implementation ConcreteHandler3
-(void)HandleRequest:(int)request{
if (request >=20 && request <30) {
NSLog(@"ConcreteHandler3處理%d", request);
}
else if (mySuccessor !=nil) {
[mySuccessor HandleRequest:request];
}
}
@end
Main方法調用
複製代碼 代碼如下:
#import <Foundation/Foundation.h>
int main(int argc,const char * argv[])
{
@autoreleasepool{
Handlers *h1 = [[ConcreteHandler1 alloc]init];
Handlers *h2 = [[ConcreteHandler2 alloc]init];
Handlers *h3 = [[ConcreteHandler3 alloc]init];
[h1 SetSuccessor:h2];
[h2 SetSuccessor:h3];
int requests[] = {2,5,14,22,18,3,27,20};
for (int i =0; i <8; i++) {
[h1 HandleRequest:requests[i]];
}
}
return 0;
}
好啦,代碼展示完畢!收工!
小結
行為型模式是對在不同的對象之間劃分責任和演算法的抽象化,行為型模式不僅僅關注類和對象的結構,而且重點關注它們之間的相互作用。通過行為型模式,可以更加清晰地劃分類與對象的職責,並研究系統在運行時執行個體對象之間的互動。行為型模式可以分為類行為型模式和對象行為型模式兩種。職責鏈模式可以避免請求寄件者與接收者耦合在一起,讓多個對象都有可能接收請求,將這些對象串連成一條鏈,並且沿著這條鏈傳遞請求,直到有對象處理它為止,它是一種對象行為型模式。
在我們日常使用中,我們或許直接接觸這方面的機會不多,但是,如果你認真有研究過程式的一場處理機制,那麼你就能夠發現這種處理機制正是採用職責鏈的方式處理常式中拋出的異常錯誤的。
在職責鏈模式裡,很多個物件由每一個對象對其下家的引用而串連起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的用戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響用戶端的情況下動態地重新組織鏈和分配責任。
職責鏈模式的主要優點在於可以降低系統的耦合度,簡化對象的相互串連,同時增強給對象指派職責的靈活性,增加新的請求處理類也很方便;其主要缺點在於不能保證請求一定被接收,且對於比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統效能將受到一定影響,而且在進行代碼調試時不太方便。
優點:
降低耦合度。
可簡化對象的相互串連。
增強給對象指派職責的靈活性。
增加新的請求處理類很方便。
缺點:
不能保證請求一定被接收。
系統效能將受到一定影響,而且在進行代碼調試時不太方便(可能會造成迴圈調用)。