责任链模式

Objective-C编程之道 iOS设计模式解析
iOS设计模式解析-工厂模式
iOS设计模式解析-抽象工厂模式
iOS设计模式解析-外观模式
iOS设计模式解析-中介者模式
iOS设计模式解析-观察者模式
iOS设计模式解析-装饰模式
iOS设计模式解析-责任链模式
iOS设计模式解析-模板方法
iOS设计模式解析-策略模式
iOS设计模式解析-享元模式
iOS设计模式解析-代码地址

何为责任链模式

责任链模式的主要思想是,对象引用了同一类型的另一个对象,形成一条链。链中的每个对象实现了同样的方法,处理对链中第一个对象发起的同一个请求。如果一个对象不知道如何处理请求,它就把请求传给下一个响应器。

责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

何时使用责任链模式

在以下情形,自然会考虑使用这一模式。

  • 有多个对象可以处理请求,而处理程序只有在运行时才能确定;
  • 向一组对象发出请求,而不想显式指定处理请求的特定处理程序。

在RPG游戏中使用责任链模式

image.png

假设要实现两种防御:金属盔甲和水晶盾牌,它们都只能按照设计对付某些攻击,金属盔甲可以防御剑的攻击,而水晶盾牌可以对付任何魔法火焰的攻击,人物也是响应链的一部分,因此它也应该跟其他防御道具具有共同的行为,对攻击做出响应。

结构

Avatar、MetalArmorCrystalShielaAttackHandler的子类。AttackHandler定义了一个方法:handleAttack:attack, 该方法的默认行为是,把攻击传给另一个AttackHandler的引用,即成员变量nextAttackHandler。子类重载这个方法,对攻击提供实际的响应。如果AttackHandler不知道如何响应一个攻击,那么就使用[super handle Attack:attack]消息,把它转发给super,这样super中的默认实现就会把攻击沿着链传下去。

AttackHandler
#import <Foundation/Foundation.h>
#import "Attack.h"

@interface AttackHandler : NSObject

@property (nonatomic, strong) AttackHandler *nextAttackHandler;

- (void) handleAttack:(Attack *)attack;

@end
#import "AttackHandler.h"

@implementation AttackHandler

- (void) handleAttack:(Attack *)attack
{
  [self.nextAttackHandler handleAttack:attack];
}

@end

AttackHandler定义了了一个同类型的变量nextAttackHandler,它是攻击的下一个响应者,AttackHandler的子类应该重载handleAttack:方法,以响应它能够识别的一种攻击。如果子类没有重载这个方法,默认的handleAttack:实现就会被调用。这个方法只是把攻击传给nextAttackHandler去处理。

MetalArmor
#import <Foundation/Foundation.h>
#import "AttackHandler.h"

@interface MetalArmor : AttackHandler

// overridden method
- (void) handleAttack:(Attack *)attack;

@end
#import "MetalArmor.h"
#import "SwordAttack.h"

@implementation MetalArmor

- (void) handleAttack:(Attack *)attack
{
  if ([attack isKindOfClass:[SwordAttack class]])
  {
    // no damage beyond this armor
    NSLog(@"%@", @"No damage from a sword attack!");
  }
  else 
  {
    NSLog(@"%@ I don't know this attack: %@",[self class],[attack class]);
    [super handleAttack:attack];
  }
}
@end
CrystalShield
#import <Foundation/Foundation.h>
#import "AttackHandler.h"

@interface CrystalShield : AttackHandler

// overridden method
- (void) handleAttack:(Attack *)attack;

@end
#import "CrystalShield.h"
#import "MagicFireAttack.h"

@implementation CrystalShield

- (void) handleAttack:(Attack *)attack
{
  if ([attack isKindOfClass:[MagicFireAttack class]])
  {
    // no damage beyond this shield
    NSLog(@"%@", @"No damage from a magic fire attack!");
  }
  else 
  {
    NSLog(@"%@ I don't know this attack: %@", [self class],[attack class]);
    [super handleAttack:attack];
  }
}

@end

如果没有防具能够对付攻击,攻击最终将传给Avatar。Avatar也是AttackHandler的子类,而且与MetalArmor和CrystalShield有相同的响应Attack的机制。但是,攻击到达这里的时候Avatar将没有防御而受到损伤。

Avatar
#import "Avatar.h"


@implementation Avatar

- (void) handleAttack:(Attack *)attack
{
  // when an attack reaches this point,
  // I'm hit.
  // actual points taken off depends on
  // the type of attack.
  NSLog(@"Oh! I'm hit with a %@!", [attack class]);
}

@end
调用
- (void)viewDidLoad {
    [super viewDidLoad];
    // create a new avatar
    AttackHandler *avatar = [[Avatar alloc] init];
    
    // put it in metal armor
    AttackHandler *metalArmoredAvatar = [[MetalArmor alloc] init];
    [metalArmoredAvatar setNextAttackHandler:avatar];
    
    // then add a crytal shield
    // to the avatar who's in
    // a metal armor
    AttackHandler *superAvatar = [[CrystalShield alloc] init];
    [superAvatar setNextAttackHandler:metalArmoredAvatar];
    
    // ... some other actions
    
    // attack the avatar with
    // a sword
    Attack *swordAttack = [[SwordAttack alloc] init];
    [superAvatar handleAttack:swordAttack];
    
    // then attack the avatar with
    // magic fire
    Attack *magicFireAttack = [[MagicFireAttack alloc] init];
    [superAvatar handleAttack:magicFireAttack];
    
    // now there is a new attack
    // with lightning...
    Attack *lightningAttack = [[LightningAttack alloc] init];
    [superAvatar handleAttack:lightningAttack];
}

这个攻击处理程序有点像栈(即先进后出)。因为需要让Avatar是攻击的最后一站,所以它要最先创建。然后创建MetalArmor的实例,把Avatar作为它的下一个AttackHandler它们被当做“增强’了的Avatar, MetalArmor 是它通往真正Avatar实例的第一道门。仅有MetalArmor还不够,还需要创建CrystalShiela的实例,作为Avatar的另一种防御。我们使用MetalArmor形式的AttackHandler ( 与Avatar连接在一起),作为CrystalShield实例的下一个攻击处理程序。此时,Avatar已是一个具有两种防御的‘ 超级人物”。在游戏中的某个时刻,我们创建了3种类型的攻击:swordAttack、 magicFireAttack和lightningAttack,让“超级人物”用它的handleAttack:方法去处理。以下是来自责任链中各种AttackHandler的输出,通过这些输出可以了解发生了什么。

输出
image.png

金属盔甲为人物挡住了剑的攻击,因为有水晶盾牌,魔法火焰攻击也没有伤到人物。但是第三次的闪电攻击,盔甲和盾牌都不知道如何应付,而是打出了消息:I don't know this attack:LightningAttack (我不认识这个攻击:闪电攻击)。最后,攻击由人物自己来处理,打出了消息oh! I'm hit with a LightningAttack! (啊!我被闪电攻击击中了!),表示因闪电攻击而受到损伤。

总结

把RPG游戏中人物的各种防御机制实现为责任链模式。每种防御机制只能应付一种特定的攻击。一个攻击处理程序链决定了人物可以防御何种攻击。在游戏过程中,任何攻击处理程序都能在任何时间被添加或删除,而不会影响人物的其他行为。对于此类设计,责任链模式是很自然的选择。否则,攻击处理程序的复杂组合会让人物的代码非常庞大,让处理程序的变更非常困难。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容