本文为原创,欢迎转载和收藏,转载请标明原文地址
程序中可能会出现大量的if-else或者switch-case来选择一系列类中的某个类进行操作,利用反射(Reflection)就可以避免这些重复判断工作。
反射在Java中封装了类来实现,在Objective-C里面要自己来实现,好在不是很难。
我们的目的是通过传入一个类名字符串,把字符串类名动态转化成类,并对类进行实例化和调用方法等操作。
OC的NSRuntime中提供了将Class name转化为Class的方法"NSClassFromString()"
NSClassFromString //方法原型 Class NSClassFromString ( NSString *aClassName );
因此,我们就可以这样使用来动态获得一个类:
NSString * aClassName = @"SunnyClass"; Class class = NSClassFromString(aClassName);
这样我们就能实例化这个类了:
id instance = [[class alloc] init];
如果需要使用方法,最好用reponseToSelector:来检测一下
if([instance reponseToSelector:@selector(aMethod)]) { [instance aMethod]; }
这样就完成了反射调用的过程。
下面就是将反射利用到工厂模式里。
定义一个Fruit,和三种继承自Fruit的水果
@interface Fruit : NSObject - (void)show; @end @interface Apple : Fruit @end @interface Banana : Fruit @end @interface Pear : Fruit @end
实现部分,简单的show方法来打印
@implementation Fruit - (void)show { NSLog(@"I'm a fruit"); } @end @implementation Apple - (void)show { NSLog(@"I'm an apple"); } @end @implementation Banana - (void)show { NSLog(@"I'm a banana"); } @end @implementation Pear - (void)show { NSLog(@"I'm a pear"); } @end
如果使用传统的if-else分支判断的话,情况就会变得非常恶心,如果想再增加一个Orange类的话,不仅需要增加Orange类的代码,工厂的代码也要新增加else-if分支:
- (Fruit *)createFruitWithName:(NSString *)fruitName { Fruit * theFruit; if ([fruitName isEqualToString:@"Apple"]) { theFruit = [[[Apple alloc] init] autorelease]; } else if ([fruitName isEqualToString:@"Banana"]) { theFruit = [[[Banana alloc] init] autorelease]; } else if ([fruitName isEqualToString:@"Pear"]) { theFruit = [[[Pear alloc] init] autorelease]; } return theFruit; }
但如果使用反射工厂的模式,情况就变得简单了许多,扩展性也会变得更好(反射输入的类名最好能来自于一个文件,这个文件规定了哪些字符串是可以作为参数传入的,这里就不考虑了)
@implementation FruitFactroy - (Fruit *)createFruitWithName:(NSString *)fruitName { //通过string得到类的结构体 Class class = NSClassFromString(fruitName); //通过转化的class得到实例对象 Fruit * theFruit = [(Fruit *)[[class alloc] init] autorelease]; //调用对象方法 if ([theFruit respondsToSelector:@selector(show)]) { [theFruit show]; } //返回对象 return theFruit; } @end
工厂方法的调用
FruitFactroy * factroy = [[[FruitFactroy alloc] init] autorelease]; Fruit * apple = [factroy createFruitWithName:@"Apple"]; Fruit * banana = [factroy createFruitWithName:@"Banana"]; Fruit * pear = [factroy createFruitWithName:@"Pear"];