jam*_*ack 8 c c++ aop dry objective-c
更新:
通过一些关键的建议和乔治来回,我提出了两种不同的方法来实现我想要的CodeRunner并将其发布在Github的gist网站上: Objective-C AOP要点
代码粗糙,因为它是一个新概念,我刚刚在凌晨1:30结束.它肯定有效,并有一些细节,如自动添加所有非初始化器,getter或setter的方法.[END UPDATE]
有几次(但肯定不是经常)我遇到过一种情况,如果我可以为类中的每个方法调用一个上下文相关的代码片段,那么我的代码会有点干扰.使用Objective-C运行时完全没问题,我也接受C或C++解决方案.
代替:
- (void)methodName1
{
self->selector = _cmd;
NSLog(@"This method is named: %@",_cmd);
//more code
}
- (void)methodName2
{
self->selector = _cmd;
NSLog(@"This method is named: %@",_cmd);
//more code
}
Run Code Online (Sandbox Code Playgroud)
有这样的事情,结果是一样的:
+ (void)AOPMethod
{
self->selector = _cmd;
NSLog(@"This method is named: %@",_cmd);
}
- (void)methodName1
{
//more code
}
- (void)methodName2
{
//more code
}
Run Code Online (Sandbox Code Playgroud)
在实际应用程序中,AOPMethod将包含更多代码,并且类中有更多方法.
PS,我对DRY非常着迷.除了散文和表现的清晰度之外,它还是我长期评估代码质量的关键因素.对于每种新方法,我都可以避免重复自己,这种好处是指数级的,因为我在许多项目共享的可重用类中尽可能多地中断代码.
对于问题中的特定用例,可以提供一个处理程序来替换原始实现函数并在处理程序之前/之后调用以及使用类似此方法之类的原始函数.一般而言,方法实现修补将不起作用,因为必须为每个截获的方法签名提供处理程序/拦截方法.
什么会更通用(即对于除变量参数函数之外的所有东西)将处理-forwardInvocation:.这里的问题是我们必须首先调用该方法.由于我们无法删除ObjC2中的方法,因此无法完成.
然而,可以做的是使用实现forwardInvocation:和调用我们的前/后处理程序的代理.
@interface AspectProxy : NSProxy {
id target_;
}
- (id)initWithTarget:(id)target;
@end
@implementation AspectProxy
- (id)initWithTarget:(id)target {
target_ = [target retain];
return self;
}
- (void)dealloc {
[target_ release];
[super dealloc];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [target_ methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)inv {
SEL sel = [inv selector];
NSLog(@"forwardInvocation for: %@", NSStringFromSelector(sel));
if (sel == @selector(aspectBefore:) || sel == @selector(aspectAfter:)) {
return;
}
if ([target_ respondsToSelector:@selector(aspectBefore:)]) {
[target_ performSelector:@selector(aspectBefore:) withObject:inv];
}
[inv invokeWithTarget:target_];
if ([target_ respondsToSelector:@selector(aspectAfter:)]) {
[target_ performSelector:@selector(aspectAfter:) withObject:inv];
}
}
@end
Run Code Online (Sandbox Code Playgroud)
因为我们不需要从init方法返回实际的实例,所以甚至可以透明地完成:
@interface Test : NSObject
- (void)someFunction;
@end
@implementation Test
- (id)init {
if (self = [super init]) {
return [[AspectProxy alloc] initWithTarget:[self autorelease]];
}
return self;
}
- (void)aspectBefore:(NSInvocation *)inv {
NSLog(@"before %@", NSStringFromSelector([inv selector]));
}
- (void)aspectAfter:(NSInvocation *)inv {
NSLog(@"after %@", NSStringFromSelector([inv selector]));
}
- (void)someFunction {
NSLog(@"some function called");
}
@end
Run Code Online (Sandbox Code Playgroud)
现在以下代码:
Test *x = [[[Test alloc] init] autorelease];
[x someFunction];
Run Code Online (Sandbox Code Playgroud)
...将打印:
forwardInvocation for:someFunction
before someFunction 之后
调用someFunction的一些函数
可以在这个要点中找到可运行的样本.
| 归档时间: |
|
| 查看次数: |
605 次 |
| 最近记录: |