iOS-OC-多态

OC三大特性:封装、继承、多态。前两种比较简单,这里讲一下多态。

一. 基本概念

  1. 多态在代码中的体现,即为多种形态,必须要有继承,没有继承就没有多态。
  2. 在使用多态时,会进行动态检测,以调用真实的对象方法。
  3. 多态在代码中的体现即父类指针指向子类对象。

多态对于面向对象思想来说,个人感觉是真的很重要,他对以后的编写代码的优雅方式也是起到很重要的作用,其实现在很多设计模式中大部分都是用到了多态的特性,Java中的多态特性用起来很是方便的,但是C++中就很难用了,其实多态说白了就是:定义类型和实际类型,一般是基于接口的形式实现的,不多说了,直接看例子吧:

二. 打印机的例子

1. 打印机类Printer

Printer.h文件

#import 

@interface Printer : NSObject  

- (void) print;  

@end  

Printer.m文件

#import "Printer.h"

@implementation Printer  
 
- (void)print{  
    NSLog(@"打印机打印纸张");  
}  
 
@end  

2. 彩色打印机类ColorPrinter

ColorPrinter.h文件

#import "Printer.h"

//修改父类的打印行为  
@interface ColorPrinter : Printer  

- (void)print;  

@end  

ColorPrinter.m文件

#import "ColorPrinter.h"

@implementation ColorPrinter  
 
- (void)print{  
   NSLog(@"彩色打印机");  
}  

@end  

3. 黑白打印机类BlackPrinter

BlackPrinter.h文件

#import "Printer.h"

@interface BlackPrinter : Printer  
 
- (void)print;  
 
@end  

BlackPrinter.m文件

#import "BlackPrinter.h"

@implementation BlackPrinter  
 
- (void)print{  
    NSLog(@"黑白打印机");  
}  
 
@end  

4. Person类

我们再定义一个Person类,用来操作具体的打印机。

Person.h文件

#import 
#import "Printer.h"
#import "ColorPrinter.h"
#import "BlackPrinter.h" 
 
@interface Person : NSObject{  
    NSString *_name;  
 }  
 
 //扩展性不高,当我们需要添加一个新的打印机的时候还要定义对应的一个方法  
 //所以这时候就可以使用多态技术了 
 //- (void)printWithColor:(ColorPrinter *)colorPrint;  
 //- (void)printWithBlack:(BlackPrinter *)blackPrint;  
 
 - (void)doPrint:(Printer *)printer;  
 
 @end  

Person.m文件

#import "Person.h"

@implementation Person  
 
/* 
   - (void)printWithColor:(ColorPrinter *)colorPrint{ 
      [colorPrint print]; 
   } 
   - (void)printWithBlack:(BlackPrinter *)blackPrint{ 
      [blackPrint print]; 
   } 
*/  
 
- (void)doPrint:(Printer *)printer{  
   [printer print];  
}  
 
@end  

5. 测试代码

main.m文件

#import 
#import "Person.h"
#import "BlackPrinter.h"
#import "ColorPrinter.h"

int main(int argc, const charchar * argv[]) {  
@autoreleasepool {  
      
    Person *person =[[Person alloc] init];  
      
    ColorPrinter *colorPrint = [[ColorPrinter alloc] init];  
    BlackPrinter *blackPrint = [[BlackPrinter alloc] init];  
      
    //多态的定义  
    /* 
    Printer *p1 = [[ColorPrinter alloc] init]; 
    Printer *p2 = [[BlackPrinter alloc] init]; 
     
    [person doPrint:p1]; 
    [person doPrint:p2]; 
     */  
      
    //通过控制台输入的命令来控制使用哪个打印机  
    int cmd;  
    do{  
        scanf("%d",&cmd);  
        if(cmd == 1){  
            [person doPrint:colorPrint];  
        }else if(cmd == 2){  
            [person doPrint:blackPrint];  
        }  
    }while (1);  
      
}  
  return 0;  
} 

三. 多态的好处

上面的例子是彩色打印机和黑白打印机两种打印机,Person类中有一个操作打印的方法,当然这个方法是需要打印机对象的,如果不用多态机制实现的话(Person.h中注释的代码部分),就是给两种打印机单独定义个操作的方法,然后在Person.m(代码中注释的部分)中对具体的打印机对象进行操作,在main.m文件中,我们看到,当Person需要使用哪个打印机的时候,就去调用指定的方法。

[person printWithBlack:blackPrint]; //调用黑白打印机  
[person printWithColor:colorPrint]; //调用彩色打印机 

这种设计就不好了,为什么呢?假如现在又有一种打印机,那么我们还需要在Person.h中定义一种操作这种打印机的方法,那么后续如果再添加新的打印机呢?还在添加方法吗?那么Person.h文件就会变得很臃肿。所以这时候多态就体现到好处了,使用父类类型,在Person.h中定义一个方法就可以了。

- (void)doPrint:(Printer *)printer;  

这里看到了,这个方法的参数类型就是父类的类型,这就是多态,定义类型为父类类型,实际类型为子类类型。

- (void)doPrint:(Printer *)printer{  
     [printer print];  
}  

这里调用print方法,就是传递进来的实际类型的print方法。

 Printer *p1 = [[ColorPrinter alloc] init];  
 Printer *p2 = [[BlackPrinter alloc] init];  
      
 [person doPrint:p1];  
 [person doPrint:p2];  

这里的p1、p2表面上是Printer类型,但是实际类型是Printer的子类类型,所以会调用他们自己对应的print方法。

四. 多态使用注意

1. 注意点

代码分析:

Dog *d = [[Animal  alloc] init];   // 动物是一条狗?语义正确吗? 错误
NSString *str = [Dog  new];     // 狗是一个字符串?正确吗?错误

OC语言是一门弱语法的语言,编译的时候并不会报错,所以这就要求我们在实际的开发过程中一定要按照既定的规范来写代码,不要出现狗是一个字符串这样的问题。

2. 多态的好处

而狗和猫实际上都继承于动物这个类,在这里就可以使用多态来简化代码了。

我们只需要把函数的参数写成是Animal *类型的,那么Dog和Cat类型的对象就都可以传入进来,调用的时候直接强转参数类型就可以了。

3. 多态的局限性

父类类型的指针变量不能直接调用子类特有的方法。

不建议的做法:

Animal *a = [[Dog alloc] init];
[a run]; //在Animal类中没有run方法

解决方法:可以将a强制转换为Dog *类型的变量,如下:

Dog *d = (Dog *)a; //使用强制转换,这里a和d指向的是同一个狗对象

五. 多态使用总结

  1. 没有继承就没有多态
  2. 代码的体现:父类类型的指针指向子类对象
  3. 好处:如果函数方法参数中使用的是父类类型,则可以传入父类和子类对象,而不用再去定义多个函数来和相应的类进行匹配了。
  4. 局限性:父类类型的变量不能直接调用子类特有的方法,如果必须要调用,则必须强制转换为子类后再调用。

你可能感兴趣的:(iOS-OC-多态)