• 设计模式(责任链模式-行为扩展)


    声明:本系列文章内容摘自《iOS设计模式》

    责任链

         谁也不是无所不知,俗话说“人多智广”。每个人都有自己的专长,将每个人的智慧连成链条,链条中的每一个单元都可以为问题的解决做出贡献。如果一个人不知道如何解决问题,他就会把这个问题沿着链条传递下去,也许有人可以解决这个问题。有时候,问题即使得到解决也依然会将问题传递下去。链条允许其中的独立单元可以进行升级和改造,而不必修改已有的单元。

    责任链的概念

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

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

    何时使用责任链模式

    1.有多个对象可以处理请求,而处理程序只有在运行时才能确定。

    2.向一组对象发送请求,而不想显式制定处理请求的特定处理程序。

    下面用RPG游戏中人物实现各种防御道具来演示该模式的使用。

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

         假定游戏中人物有两种防具,一种是防御物理刀剑伤害的金属铠甲和防御魔法伤害的水晶盾牌,攻击包括刀枪伤害和魔法伤害。已盾牌作为第一层防御抵挡攻击,如果抵挡不了就将攻击传递给金属铠甲,金属铠甲如果也不能够抵御伤害,那么就将攻击传递到人物本身上来。用下图来描述:

    图1

    图2

    代码实现

           Avatar(人物)、MetalArmor(金属铠甲)和CrystalShield(水晶盾)是AttackHandler(攻击控制类)的子类。AttackHandler定义了一个方法——handleAttack:attack,该方法的默认行为是,把攻击传给另一个AttackHandler的引用,即成员变量nextAttackHandle_。子类重载这个方法,对攻击提供实际的响应,如果AttackHandler不知道如何响应一个攻击,那么就使用[super handleAttack:attack]消息,把攻击转发给super,这样super中的默认实现就会把攻击沿着链传递下去。

          有三种攻击方式,SwordAttack(刀剑攻击)、MagicFireAttack(魔法攻击)和LightningAttack(雷电攻击),下面将讨论AttackHandler如何响应各种攻击。

    首先看一下AttackHandler父类的代码实现:

    #import "Attack.h"
    
    @interface AttackHandler : NSObject
    
    {
        @private
        AttackHandler *nextAttackHandler_;
    }
    
    @property (nonatomic, retain) AttackHandler *nextAttackHandler;
    
    -(void)handleAttack:(Attack *)attack;
    
    @end
    

     AttackHandler定义了一个同类型的私有变量nextAttackHandler_,它是攻击的下一个响应者。AttackHandler的子类应该重载handleAttack:方法,以响应它能够识别的一种攻击。抽象的AttackHandler为这个方法定义了默认行为。

    #import "AttackHandler.h"
    
    @implementation AttackHandler
    
    @synthesize nextAttackHandler = nextAttackHandler_;
    
    -(void)handleAttack:(Attack *)attack
    {
        [nextAttackHandler_ handleAttack:attack];
    }
    

     然后看一下第一个防具防具MetalArmor。

    MetalArmor子类化AttackHandler并重载其中的handleAttack:方法。

    #import "AttackHandler.h"
    
    @interface MetalArmor : AttackHandler
    
    //重载方法(不是必须写)
    -(void)handleAttack:(Attack *)attack;
    
    @end
    
    #import "MetalArmor.h"
    #import "SwordAttack.h"
    
    @implementation MetalArmor
    
    -(void)handleAttack:(Attack *)attack
    {
        if ([attack isKindOfClass:[SwordAttack class]]) {
            NSLog(@"攻击没有通过这个金属盔甲");
        }
        else
        {
            NSLog(@"不能识别这个攻击:%@",[attack class]);
            [super handleAttack:attack];
        }
    }
    
    @end
    

     魔法护盾同理也是这样写。

    然后看一下人物(Avatar)类,它本身页是AttackHandler的子类,攻击到这里的时候就伤害到的人物本身。

    #import "Avatar.h"
    
    @implementation Avatar
    
    -(void)handleAttack:(Attack *)attack
    {
        //实际损伤点数取决于攻击类型
        NSLog(@"我被%@攻击到了",[attack class]);
    }
    
    @end

    下面就是管理攻击和人物的代码:

    //创建人物
        _avatar = [[Avatar alloc] init];
        
        //穿金属甲
        _metalArmored = [[MetalArmor alloc] init];
        [_metalArmored setNextAttackHandler:_avatar];
        
        //穿水晶盾
        _crystalShield = [[CrystalShield alloc] init];
        [_crystalShield setNextAttackHandler:_metalArmored];
        
        _swordAttack = [[SwordAttack alloc] init];
        _magicFireAttack = [[MagicFireAttack alloc] init];
        _lightningAttack = [[LightningAttack alloc] init];
    
    switch (attackType)
            {
                case SwordAttackType:
                {
                    [_crystalShield handleAttack:_swordAttack];
                    _bloodCount -= 1;
                }
                    break;
                case MagicFireAttackType:
                {
                    [_crystalShield handleAttack:_magicFireAttack];
                    _bloodCount -= 2;
                }
                    break;
                case LightningAttackType:
                {
                    [_crystalShield handleAttack:_lightningAttack];
                    _bloodCount -= 5;
                }
                    break;
                    
                default:
                    break;
            }

    这个简单地RPG游戏的例子演示了如何使用责任链模式,来简化任务处理各种攻击的编码和逻辑。如果不用这个模式,防御逻辑很可能都塞到一个类中(如AVAtar中),代码会乱作一团。

    总结

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

    Demo地址:https://github.com/haozheMa/DesignPatternsCollections

  • 相关阅读:
    3.默认参数的注意事项
    2.关键字global,nonlocal
    1.函数的结构,调用,传参,形参,实参,args,kwargs,名称空间,高阶函数
    19. 实现一个整数加法计算器(多个数相加):
    20.文件操作
    18.使用for循环计算+1-3+5-7+9-11+13...99的结果
    ubuntu docker更新镜像源
    虚拟环境的使用
    前端基础之HTML
    jQuery基本使用
  • 原文地址:https://www.cnblogs.com/wlsxmhz/p/6094274.html
Copyright © 2020-2023  润新知