動態代理模式的應用很多,特別是在不能修改被代理類的前提下,要對執行某些方法時需要打log或者捕捉異常等處理時,是一個非常方便的方法。只需要少量修改客戶端(場景類)代碼和添加一個代理類就可以實現,這個符合Open-Close Principle。
在Java和.Net中的AOP也是利用了這種代理模式的實現。
iOS實現的代碼如下:
首先,定義一個接口,
@protocol DPDynamicProtocol <NSObject> @required - (void)doSomething; - (void)doOtherThing; @end
這個接口做兩件事,doSomething和doOtherThing。
被代理類需要實現這個接口(不實現其實也可以,只是設計不好,每一個類都應該實現接口或者繼承自一個抽象類)。
#import "DPDynamicProtocol.h" @interface DPNormalObject : NSObject <DPDynamicProtocol> @end
@implementation DPNormalObject
- (void)doSomething {
NSLog(@"normal object do something");
}
- (void)doOtherThing {
NSLog(@"normal object do other thing");
}
@end
同時,代理類也實現DPDynamicProtocal接口,並且繼承自NSProxy這個類。
#import "DPDynamicProtocol.h"
@interface DPDynamicProxy : NSProxy <DPDynamicProtocol> {
@private
id<DPDynamicProtocol> _obj;
}
- (id)initWithObject:(id<DPDynamicProtocol>)obj;
@end
@implementation DPDynamicProxy
- (id)initWithObject:(id<DPDynamicProtocol>)obj {
_obj = obj;
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if (_obj) {
NSLog(@"proxy invocation obj method : %s", [invocation selector]);
[invocation setTarget:_obj];
[invocation invoke];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
if ([_obj isKindOfClass:[NSObject class]]) {
return [(NSObject *)_obj methodSignatureForSelector:sel];
}
return [super methodSignatureForSelector:sel];
}
- (void)doSomething {
NSLog(@"proxy do something");//1
[_obj doSomething];
}
@end
這樣,就可以很好的在被代理類NPNormalObject的doSomething方法前添加log或者捕捉異常了。
對於場景類的修改:
- (void)clientInvoke {
// id<DPDynamicProtocol> obj = [[DPNormalObject alloc] init]; // 2
id<DPDynamicProtocol> obj = [[DPDynamicProxy alloc] initWithObject:[[DPNormalObject alloc] init]]; // 3
[obj doSomething];
[obj doOtherThing];
}
只需要將2改為3即可。
