本文為原創,歡迎轉載和收藏,轉載請標明原文地址
程序中可能會出現大量的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"];