美文网首页
OC中的多态

OC中的多态

作者: 一叶知秋0830 | 来源:发表于2019-06-28 13:15 被阅读0次

    一、多态的概念

    一说起面向对象语言的三大特性,你可能会脱口而出:封装、继承、多态。那什么是多态呢,你或许可以背出关于多态的定义,可以举出关于猫、狗吃东西的例子,但你真的理解多态在程序设计中的妙用吗?恐怕不尽然,尤其是对于一些刚接触面向对象的童鞋来说,不明白为什么要在程序中使用多态。
    那到底什么是多态呢?从字面上来理解,多态就是多种形态,其在代码上的体现就是父类指针指向之类对象。所以说多态必须要有继承(不理解继承的同学自己去查资料,这里不做讲解),不同的子类重写父类的方法,当父类指针指向不同子类时,其调用同样的方法可以体现出不同的行为。额!这个概念好抽象,越看越懵逼。好吧,就不在概念上深究了,直接通过实例来讲解吧。

    二、项目需求

    多态在实际项目中运用很广,下面以回合制的卡牌游戏为例来讲解多态的使用。
    游戏卡牌英雄分3种职业,分别是战士、法师、术士,不同职业的英雄攻击方式各不相同,我们可以同时上阵5个英雄(比如2个法师2个术士1个战士),轮到我方回合时,上阵的5个英雄轮流发起攻击。
    下面我们来看看不使用多态和使用多态两种方式来实现这个需求。

    三、不使用多态来实现需求

    每个职业创建一个类,分别实现它们的攻击方法。然后创建一个英雄管理类,在这个类中初始化5个英雄放入一个数组,然后遍历数组取出每个英雄进行攻击。先来看看具体代码吧:

    战士类

    /*战士*/
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Warrior : NSObject
    
    /**
     战士攻击
     */
    - (void)warriorAttack;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Warrior.h"
    
    @implementation Warrior
    
    - (void)warriorAttack{
        // 战士的攻击方式
        NSLog(@"战士进行攻击");
    }
    
    @end
    

    法师类

    /*法师*/
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Mage : NSObject
    
    /**
     法师攻击
     */
    - (void)mageAttack;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Mage.h"
    
    @implementation Mage
    
    - (void)mageAttack{
        // 法师的攻击方式
        NSLog(@"法师进行攻击");
    }
    
    @end
    

    术士类

    /*术士*/
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Warlock : NSObject
    
    /**
     术士攻击
     */
    - (void)warlockAttack;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    /*术士*/
    #import "Warlock.h"
    
    @implementation Warlock
    
    - (void)warlockAttack{
        // 术士的攻击方式
        NSLog(@"术士进行攻击");
    }
    
    @end
    

    英雄管理类

    #import "HeroManager.h"
    #import "Warrior.h"
    #import "Mage.h"
    #import "Warlock.h"
    
    @implementation HeroManager
    {
        NSArray *_heroArr;
    }
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            [self createHero];
            [self heroAttack];
        }
        return self;
    }
    
    // 创建英雄
    - (void)createHero{
        // 2个法师
        Mage *mage1 = [[Mage alloc] init];
        Mage *mage2 = [[Mage alloc] init];
        
        // 2个术士
        Warlock *warlock1 = [[Warlock alloc] init];
        Warlock *warlock2 = [[Warlock alloc] init];
        
        // 1个战士
        Warrior *warrior1 = [[Warrior alloc] init];
        
        _heroArr = @[mage1,mage2,warlock1,warlock2,warrior1];
        
    }
    
    // 英雄攻击
    - (void)heroAttack{
        for (NSInteger i = 0; i < _heroArr.count; i++) {
            if ([_heroArr[i] isKindOfClass:[Warrior class]]) {
                // 判断如果是战士类型就进行战士攻击
                Warrior *warrior = (Warrior *)_heroArr[i];
                [warrior warriorAttack];
            }else if ([_heroArr[i] isKindOfClass:[Mage class]]) {
                // 判断如果是法师类型就进行法师攻击
                Mage *mage = (Mage *)_heroArr[i];
                [mage mageAttack];
            }else if ([_heroArr[i] isKindOfClass:[Warlock class]]) {
                // 判断如果是术士类型就进行术士攻击
                Warlock *warlock = (Warlock *)_heroArr[i];
                [warlock warlockAttack];
            }
        }
    }
    
    @end
    

    运行结果如下:

    2019-06-27 09:43:46.172172+0800 abc[22549:4026177] 法师进行攻击
    2019-06-27 09:43:46.172607+0800 abc[22549:4026177] 法师进行攻击
    2019-06-27 09:43:46.172623+0800 abc[22549:4026177] 术士进行攻击
    2019-06-27 09:43:46.172635+0800 abc[22549:4026177] 术士进行攻击
    2019-06-27 09:43:46.172646+0800 abc[22549:4026177] 战士进行攻击
    

    从上面英雄攻击的方法可以看出,每次攻击时都需要判断当前攻击的英雄是什么职业,然后再调用相应职业的攻击方法。现在只有3个职业,如果是10个职业呢,那这个方法里面就会有10个if……else if的判断,而且如果游戏更新,新增加了一个职业,那么这个方法又要进行改动,又要添加一个else if的判断,程序拓展起来非常的不灵活。

    三、使用多态来实现需求

    使用多态时先创建一个英雄父类,父类里面有个攻击的方法,然后每个职业都继承自这个父类并重写攻击的方法。下面看下具体代码的实现:

    英雄父类

    /*英雄父类*/
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Hero : NSObject
    /**
     攻击
     */
    - (void)attack;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Hero.h"
    
    @implementation Hero
    
    @end
    

    战士类

    /*战士*/
    #import "Hero.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Harrior : Hero
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Harrior.h"
    
    @implementation Harrior
    
    // 重写父类攻击方法
    - (void)attack{
        // 战士的攻击方式
        NSLog(@"战士进行攻击");
    }
    
    @end
    

    法师类

    /*法师*/
    #import "Hero.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Mage : Hero
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Mage.h"
    
    @implementation Mage
    
    // 重写父类攻击方法
    - (void)attack{
        // 法师的攻击方式
        NSLog(@"法师进行攻击");
    }
    
    @end
    

    术士类

    /*术士*/
    #import "Hero.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Warlock : Hero
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "Warlock.h"
    
    @implementation Warlock
    
    // 重写父类攻击方法
    - (void)attack{
        // 术士的攻击方式
        NSLog(@"术士进行攻击");
    }
    
    @end
    

    英雄管理类

    #import "HeroManager.h"
    #import "Warrior.h"
    #import "Mage.h"
    #import "Warlock.h"
    
    @implementation HeroManager
    {
        NSArray *_heroArr;
    }
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            [self createHero];
            [self heroAttack];
        }
        return self;
    }
    
    - (void)createHero{
        
        // 2个法师
        Mage *mage1 = [[Mage alloc] init];
        Mage *mage2 = [[Mage alloc] init];
        
        // 2个术士
        Warlock *warlock1 = [[Warlock alloc] init];
        Warlock *warlock2 = [[Warlock alloc] init];
        
        // 1个战士
        Warrior *warrior1 = [[Warrior alloc] init];
        
        _heroArr = @[mage1,mage2,warlock1,warlock2,warrior1];
        
    }
    
    // 英雄攻击
    - (void)heroAttack{
        for (NSInteger i = 0; i < _heroArr.count; i++) {
            Hero *hero = (Hero *)_heroArr[i];
            [hero attack];
        }
    }
    
    @end
    

    从上面英雄攻击的方法可以看出,当父类指针指向子类时,调用attack方法时它会根据子类的类型去进行不同的攻击,我们完全不用关心也不用判断英雄的职业。这样设计代的话码少了很多,而且就算有10个、100个职业,heroAttack方法里面完全不用改的,新增职业时这里也不需要变动,拓展起来就灵活了很多。

    相关文章

      网友评论

          本文标题:OC中的多态

          本文链接:https://www.haomeiwen.com/subject/gwzkcctx.html