iOS設計模式--責任鏈模式
原文地址:http://my.oschina.net/daguoshi/blog/495573?fromerr=9lqAJyi7
何為責任鏈模式?
責任鏈模式的主要思想是,物件引用了同一型別的另一個物件,形成一條鏈。鏈中的每個物件實現了同樣的方法,處理對鏈中第一個物件發起的同一個請求。如果一個物件不知道如何處理請求,它就把請求傳遞給下一個響應者。
責任鏈模式:使多個物件都有機會處理請求,從而避免請求的傳送者和接收者之間發生耦合。此模式將這些物件連成一條鏈,並沿著這條鏈傳遞請求,直到有一個物件處理它為止。
何時使用責任鏈模式?
@:有多個物件可以處理請求,而處理程式只有在執行時才能確定。
@:向一組物件發出請求,而不想顯示指定處理請求的特定處理程式。
在遊戲中使用責任鏈模式
假定我們要開發一款遊戲,裡面的每個人物都可以通過做任務賺取點數來升級防禦道具。防禦道具可以使盾牌或者盔甲。每種形式的防禦只能應付一種特定的攻擊,如果防禦道具不認識一種進攻,它就把進攻的作用傳遞給下一個會響應它的實體。比如,盔甲1不知道如何對付對手的攻擊,所以把它傳給下一個盔甲,盔甲2。盔甲2剛好知道如何對付這次攻擊,化解了人物可能受到的損傷。由於某種原因,如果沒有盔甲可以對這次攻擊做出響應,攻擊的作用最終會傳到人物。人物對攻擊做出響應時,會表現為一定程度的損傷。
這種只讓每個獨立的防禦道具對特定型別的攻擊做出相應的機制,簡化了人物使用各種防禦道具的複雜性。每種盔甲各自負責非常特定的功能。這就是責任鏈模式的作用所在。
下面我們將使用責任鏈模式實現這個設計,假設有兩種防禦:水盔甲和火盔甲。它們都只能按照設計對付某些攻擊。水盔甲可以防禦來自水的攻擊,火盔甲可以防禦來自火的攻擊。人物也是響應鏈的一部分,因此它也應該跟其他防禦道具具有共同的行為,對攻擊做出響應。
WaterAttackHandler、FireAttackHandler和Avatar是AttackHandler的子類。AttackHandler定義了一個方法——handleAttack:attack,該方法的預設行為是,把攻擊傳給另一個AttackHandler的引用,即成員變數nextAttackHandler。子類過載這個方法,對攻擊提供實際的響應。如果AttackHandler不知道如何響應一個攻擊,那麼就使用[super handleAttack:attack];訊息,把它轉發給super,這樣super的預設實現就會把攻擊沿著鏈給傳下去。
定義3中型別的攻擊,WaterAttack、FireAttack、SoliderAttack。先看下AttackHandler父類的程式碼,程式碼如下:
?1 2 3 4 5 6 7 8 9 |
#import <Foundation/Foundation.h>
#import "Attack.h"
@interface AttackHandler : NSObject
@property (nonatomic, strong) AttackHandler *nextAttackHandler;
- ( void )handleAttack:(Attack *)attack;
@end
|
AttackHandler定義了一個同類型的私有變數nextAttackHandler,它是攻擊的下一個響應者。AttackHander的子類應該過載handleAttack:方法,以響應它能夠識別的一種攻擊。抽象的AttackHandler為這個方法定義了預設行為,程式碼如下:
?1 2 3 4 5 6 7 8 9 10 |
#import "AttackHandler.h"
@implementation AttackHandler
- ( void )handleAttack:(Attack *)attack {
// 預設呼叫nextAttackHandler進行處理。
[_nextAttackHandler handleAttack:attack];
}
@end
|
如果子類沒有過載這個方法,預設的handleAttack:實現就會被呼叫。這個方法只是把攻擊傳給nextAttackHandler去處理。
接下來看下任務的第一個防禦道具WaterAttackHandler,WaterAttackHandler子類化AttackHandler並重載其handleAttack:方法,程式碼如下:
?1 2 3 4 5 6 7 8 |
#import "AttackHandler.h"
@interface WaterAttackHandler : AttackHandler
// 重寫處理攻擊方法
- ( void )handleAttack:(Attack *)attack;
@end
|
在.h中再次宣告過載的方法不是必需的,但是這樣做更加清晰。WaterAttackHandler只能識別WaterA