Objective-C编程之道 iOS设计模式解析
iOS设计模式解析-工厂模式
iOS设计模式解析-抽象工厂模式
iOS设计模式解析-外观模式
iOS设计模式解析-中介者模式
iOS设计模式解析-观察者模式
iOS设计模式解析-装饰模式
iOS设计模式解析-责任链模式
iOS设计模式解析-模板方法
iOS设计模式解析-策略模式
iOS设计模式解析-享元模式
iOS设计模式解析-代码地址
何为责任链模式
责任链模式的主要思想是,对象引用了同一类型的另一个对象,形成一条链。链中的每个对象实现了同样的方法,处理对链中第一个对象发起的同一个请求。如果一个对象不知道如何处理请求,它就把请求传给下一个响应器。
责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
何时使用责任链模式
在以下情形,自然会考虑使用这一模式。
- 有多个对象可以处理请求,而处理程序只有在运行时才能确定;
- 向一组对象发出请求,而不想显式指定处理请求的特定处理程序。
在RPG游戏中使用责任链模式
假设要实现两种防御:金属盔甲和水晶盾牌,它们都只能按照设计对付某些攻击,金属盔甲可以防御剑的攻击,而水晶盾牌可以对付任何魔法火焰的攻击,人物也是响应链的一部分,因此它也应该跟其他防御道具具有共同的行为,对攻击做出响应。
结构
Avatar、MetalArmor和CrystalShiela是AttackHandler的子类。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的输出,通过这些输出可以了解发生了什么。
输出
金属盔甲为人物挡住了剑的攻击,因为有水晶盾牌,魔法火焰攻击也没有伤到人物。但是第三次的闪电攻击,盔甲和盾牌都不知道如何应付,而是打出了消息:I don't know this attack:LightningAttack (我不认识这个攻击:闪电攻击)。最后,攻击由人物自己来处理,打出了消息oh! I'm hit with a LightningAttack! (啊!我被闪电攻击击中了!),表示因闪电攻击而受到损伤。
总结
把RPG游戏中人物的各种防御机制实现为责任链模式。每种防御机制只能应付一种特定的攻击。一个攻击处理程序链决定了人物可以防御何种攻击。在游戏过程中,任何攻击处理程序都能在任何时间被添加或删除,而不会影响人物的其他行为。对于此类设计,责任链模式是很自然的选择。否则,攻击处理程序的复杂组合会让人物的代码非常庞大,让处理程序的变更非常困难。