OC中的多态

一、多态的概念

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

二、项目需求

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

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

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

战士类

/*战士*/
#import 

NS_ASSUME_NONNULL_BEGIN

@interface Warrior : NSObject

/**
 战士攻击
 */
- (void)warriorAttack;

@end

NS_ASSUME_NONNULL_END
#import "Warrior.h"

@implementation Warrior

- (void)warriorAttack{
    // 战士的攻击方式
    NSLog(@"战士进行攻击");
}

@end

法师类

/*法师*/
#import 

NS_ASSUME_NONNULL_BEGIN

@interface Mage : NSObject

/**
 法师攻击
 */
- (void)mageAttack;

@end

NS_ASSUME_NONNULL_END
#import "Mage.h"

@implementation Mage

- (void)mageAttack{
    // 法师的攻击方式
    NSLog(@"法师进行攻击");
}

@end

术士类

/*术士*/
#import 

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 

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中的多态)