1. 程式人生 > >iOS設計模式--責任鏈模式

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