您的位置:首页 > 移动开发 > Objective-C

MUWork--一个基于Objective-c的AOP开发框架

2012-07-29 13:36 537 查看
先啥都不说,看一下MUWork的使用例子,让我们通过代码来感性地认识一下这是个什么东西。

首先,你的程序里必须要有这些文件:



然后我们声明一个类:

#import <Foundation/Foundation.h>
#import "MUActionProtocol.h"

@interface TestAction : NSObject<MUActionProtocol> {
}

@property(nonatomic, strong) NSString* name;

@end


实现它:

#import "TestAction.h"

@implementation TestAction

@synthesize name = _name;

- (id)execute
{
NSLog(@"name: %@", _name);
return [NSString stringWithFormat:@"Action invoked:%@", _name];
}

@end


再声明一个TestInteceptor类:

#import <Foundation/Foundation.h>
#import "MUInterceptorProtocol.h"

@interface TestInterceptor : NSObject<MUInterceptorProtocol> {
}

@end

实现它

#import "TestInterceptor.h"
#import "MUHandler.h"

@implementation TestInterceptor

- (BOOL) actionBefore:(MUHandler*) handler
{
NSLog(@"actionBefore was invoked.");
return YES;
}
- (void) actionAfter:(MUHandler*) handler
{
NSLog(@"actionAfter was invoked.");
}

@end


OK,我们来下一步。

在主程序里,我们可以这样写:

TestMUInterceptor* interceptor = [[TestMUInterceptor alloc] init];
TestAction* action = [[TestAction alloc] init];
DefaultMUResult* result = [[DefaultMuResult alloc] init];

MUHandler* handler = [[MUHandler alloc] init];
[handler setAction:action];
[handler setResult:result];
[handler addInterceptor:interceptor];
[handler setContextObject:@"abc" forKey:@"name"];

MUInvocation* invocation = [[MUInvocation alloc] init];
NSLog(@"%@", [invocation invoke:handler]);


我们运行一下程序,会输出什么呢?
2012-07-29 11:01:49.740 TestMUWork[537:5d03] actionBefore was invoked.
2012-07-29 11:01:49.741 TestMUWork[537:5d03] name: abc
2012-07-29 11:01:49.742 TestMUWork[537:5d03] actionAfter was invoked.
2012-07-29 11:01:49.744 TestMUWork[537:5d03] Action invoked:abc


改一下这句:

[handler addInterceptor:interceptor];
//改成:
[handler addInterceptor:interceptor];
[handler addInterceptor:[interceptor copy]];
[handler addInterceptor:[interceptor copy]];


再运行一下,输出下面的结果:

2012-07-29 11:01:49.740 TestMUWork[537:5d03] actionBefore was invoked.
2012-07-29 11:01:49.780 TestMUWork[537:5d03] actionBefore was invoked.
2012-07-29 11:01:49.860 TestMUWork[537:5d03] actionBefore was invoked.
2012-07-29 11:01:49.920 TestMUWork[537:5d03] name: abc
2012-07-29 11:01:49.980 TestMUWork[537:5d03] actionAfter was invoked.
2012-07-29 11:01:50.005 TestMUWork[537:5d03] actionAfter was invoked.
2012-07-29 11:01:50.015 TestMUWork[537:5d03] actionAfter was invoked.
2012-07-29 11:01:50.035 TestMUWork[537:5d03] Action invoked:abc


看完上面的例子,相信有不少人已经很清楚MUWork是干什么的了。那么,下面开始正式介绍MUWork。

1.    MUWork是什么

先来看一下百度百科里面关于XWork的简介:

XWork是一个标准的Command模式实现,并且完全从web层脱离出来。Xwork提供了很多核心功能:前端拦截机(interceptor),运行时表单属性验证,类型转换,强大的表达式语言(OGNL – the Object Graph Navigation Language),IoC(Inversion ofControl反转控制)容器等。

那么,不准确地,MUWork可以概述为:

MUWork是受XWork启发而实现的一个基于Objective-c 语言的Command模式实现。MUWork的实现参照了Struts2的架构,省去了容器部分,由MUAction、MUConfig、MUHandler、MUInterceptor、MUInvocation、MUResult、MUValueStack七个组件构成。其目的是:创建一个泛化的、可重用且可扩展的命令模式框架。

大致可以用下图表示:



2.    MUWork的结构

MUWork由七个组件构成,大致可以用下图表示:

1.    MUAction:

        据我自己的不完全理解,action类代表了业务的核心操作,是处理“你要完成的事情”的地方。

        先来看一下Action类的接口:

#import <Foundation/Foundation.h>

@protocol MUActionProtocol <NSObject>

- (id)execute;

@end

           注意到该接口只声明一个方法Execute,该方法返回一个id类型的变量。这里的返回值就是核心业务操作的返回结果。

        可以看到,execute方法并没有参数,那么业务运算时所需要的数据怎么传入呢?事实上,Action类是通过声明属性获得所有相关的值的。要对action进行数据交互,我们要做的唯一一件事就是在Action类中声明与参数同名的属性,在调用Action的execute方法之前,调度器(MUInvocation)就会为相应的Action属性赋值(注入)。这个功能的实现很大程度依赖于MUValueStack,MUValueStack为访问Action属性提供了一个很方便的途径。

2.    MUInterceptor:

顾名思义,MUInterceptor为拦截器,是实现AOP的核心元素。借用一下downpour在《拦截器详解》里面对interceptor的定义:

Interceptor本身是AOP的概念,表示对程序的某个逻辑执行点进行拦截,从而能够在
4000
这个逻辑执行点之前、之后或者环绕着这个逻辑执行点进行逻辑扩展。在XWork中,Interceptor的拦截对象是核心处理类Action,从而在Action的周围定义了一个环绕的逻辑扩展层次,其主要作用就在于能够在核心处理类Action的执行之前、之后进行自定义的逻辑行为扩展。

我们来看一下MUInterceptor的接口:

#import <Foundation/Foundation.h>
@class MUHandler;

@protocol MUInterceptorProtocol <NSObject>

@optional
- (BOOL) actionBefore:(MUHandler*) handler;
- (void) actionAfter:(MUHandler*) handler;

@end

       可以看到该接口定义了两个可选方法:

- (BOOL) actionBefore:(MUHandler*) handler;
- (void) actionAfter:(MUHandler*) handler;

       从方法名字可以看出,它们分别在action执行前和执行后调用。其中actionBefore:方法的返回结果决定了业务操作是否继续进行。

3.    MUResult:

#import <Foundation/Foundation.h>

@protocol MUResultProtocol <NSObject>

- (id)parseResult:(id) result

@end

       MUResult实现了返回结果和表现形式的解耦。在整个command流的最后,MUResult中的parseResult:方法会被调用,返回结果在其中进行最后的包装。

4.    MUHandler:

#import <Foundation/Foundation.h>
#import "MUInterceptorProtocol.h"
#import "MUActionProtocol.h"
#import "MUResultProtocol.h"
#import "MUValueStack.h"

@interface MUHandler : NSObject {
NSMutableDictionary* _contextDictionary;
NSMutableArray* _interceptorArray;
id<MUActionProtocol> _action;
id<MUResultProtocol> _result;
MUValueStack* _valueStack;
}

@property(nonatomic, strong) id<MUActionProtocol> action;
@property(nonatomic, strong) id<MUResultProtocol> result;
@property(nonatomic, readonly) MUValueStack* valueStack;
@property(nonatomic, strong) NSMutableArray* interceptorArray;
@property(nonatomic, copy) NSString* name;

//interceptor
- (void) addInterceptor:(id<MUInterceptorProtocol>) interceptor;
- (void) removeInterceptorAtIndex:(NSInteger) index;
- (void) removeInterceptor:(id<MUInterceptorProtocol>) interceptor;

//context
- (void) setContextObject:(id) object forKey:(id) key;
- (id)   contextObjectForkey:(id) key;
- (void) removeContextObject:(id) key;
- (NSDictionary*) contextDictionary;

@end
        MUHandler是Action、interceptor、result、ValueStack实例的载体,同时其内部维护着一个contextDictionary,是整个业务过程中的数据载体。从其中的方法可以看出,通过handler可以添加或者删除interceptor,或者增删contextDictionary里面的数据。可以总结为:MUHandler既是控制流的访问接口,同时也是数据流的访问接口,可以利用interceptor通过handler对控制流和数据流进行操作,以实现command模式。

5.    MUValueStack:

#import <Foundation/Foundation.h>
#import "MUSimpleEL.h"

@interface MUValueStack : NSObject {
NSMutableArray* _objectArray;
MUSimpleEL* _simpleEL;
}

- (void)pushObject:(id) object;
- (id)popObject;
- (id)peek;

- (id)getValue:(NSString*) expression;
- (void)setValue:(NSString*) expression value:(id) value;

@end

MUValueStack和Structs里面的ValueStack类似,是数据访问的工具,其内部维护着一个小型表达式解释器MUSimpleEL,通过表达式语言对action的属性进行访问和设置。

6.    MUInvocation:

#import <Foundation/Foundation.h>
#import "MUHandler.h"

@interface MUInvocation : NSObject {
}

- (id)invoke:(MUHandler*) handler;
- (id)onlyInvokeAction:(MUHandler*) handler;

@end
MUInvocation是整个command流的总调度器,负责interceptor和action调用的次序。当Handler初始化完毕后,传入invocation的invoke方法,整个command模式即可启动。
其中only方法是提供一种不触发拦截器直接执行action的调用途径。

7.    MUConfig:

#import <Foundation/Foundation.h>
#import "MUHandler.h"

@protocol MUConfigProtocol <NSObject>

+ (MUHandler*) getHandler:(NSInteger) type;

@end
MUConfigProcotol是一个辅助MUHandler进行初始化的简单工厂接口。

8.    其他:

MUActionInjector

#import <Foundation/Foundation.h>
#import "MUActionProtocol.h"
#import "MUHandler.h"
@interface MUActionInjector : NSObject

+ (void) injectHandler:(MUHandler*) handler intoAction:(id<MUActionProtocol>) action;

@end
#import "DefaultMUResult.h"
@implementation DefaultMUResult

- (id)parseResult:(id) result
{
return result;
}
@end
此类主要是负责自动地对action进行属性注入。虽然可以通过设置Interceptor和valuestack完成这样的工作,但是这里为了不在业务流里掺杂与框架相关的操作流,所以交给了一个特定的类来进行。

MUSimpleEL

#import <Foundation/Foundation.h>

@interface MUSimpleEL : NSObject

- (id)executeExpression:(NSString*) expression context:(NSDictionary*) context root:(id) root;

@end

MUSimpleEL是一个非常简单的表达式解释器。

MUDefaultResult

#import "DefaultMUResult.h"

@implementation DefaultMUResult

- (id)parseResult:(id) result
{
return result;
}

@end


MUResultProtocol的默认实现,只是简单地把传入参数返回。

3.    源码下载

源码已上传到GitHub,点击下载源代码

4.基于MUWork的一些东西

写完这个框架以后,我决定要用它来做点什么。由于我是一个ios开发者,所以打算把MUWork用在这一方面。经过几天的努力和几十天的修改,有了下面的东西:

MUNavigator

MUNavigator是一个基于MUWork的ios开发框架,通过AOP实现了业务逻辑流和界面逻辑流的分离,他可以令你的ViewController里面只有跟界面有关的代码,所有业务逻辑交给Handler处理,并且提供一个相对完善的Delegate回调机制。

关于这部分的文档正在整理中,到时另外一文进行介绍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐