Spring ActionScript Operation API入门教程[一]:简介
在Spring ActionScript 1.0 RC版本中,包含了一个Operation API,今天我们就来对这个部分做个简单介绍。在之后的文章中,我们将练习使用Operation API来完成一个简单的示例。
Operation API简介
在很多Flash或Flex应用中有一个共性:他们都需要连接到后端获取数据,比如:呼叫一个远程对象,加载一个二级模块或资源文件,这些方式也有一个共性:他们都是异步的。而Flex框架和Flash Player看起来为不同类型的数据检索提供了不同的异步模式,比如回调方法,基于事件的方法,呼叫一个实例返回一个IEventDispatcher或其它接口,等等。这些看起来有些混乱,也使我们的编程方式看起来不统一。
在这种情况下,Spring ActionScript Operation API出现了,它提供了一种通用的方式,包含了上面不同的模式并非常易于使用。它提供了一些类和接口来让开发者非常容易编写他们的逻辑,同样对于一些通用的任务,Spring ActionScript也提供了支持,比如加载Flex模块,资源模块和远程对象调用。
注意Operation API不是一个MVC或MVCS框架,作者认为提供一个框架过于僵硬,不如给开发者提供一套基础的接口和类更方便他们的使用。每个应用都有自己的特点,而Operation API的灵活和便捷将使它很容易整合到应用中。
Operations, commands, services and tasks
如标题所述,Operation API包含4个部分:
-
Operation: 一个异步的动作.
-
Command: 一个延期执行的动作.
-
Service:一组相关的Operation的集合.
-
Task: 一组被工作流控制的Command的集合.
Operation(操作)
操作是一个异步的动作,比如我们向服务器发送一次请求,然后稍等片刻,获取到了服务器返回的数据,可以将这个过程抽象为一个操作。在编程层面,我们把一个操作对应到具体的类,则这个类需要实现操作的接口:
function get result():*; function get error():*; }
注意这个接口规范了异步的操作模式,包括返回的结果或错误,对过程使用事件侦听。如果你需要侦听数据的加载进度,则要实现下面的接口:
public interface IProgressOperation extends IOperation { }
操作可以说是Operation API概念中的最小单元,因为其有规范的接口,我们可以很方便的在Command和Service等部分来使用它。我们甚至可以把若干小的操作集合起来使用,这就要用到OperationQueue类,示例如下:
var queue:OperationQueue = new OperationQueue(); queue.addCompleteListener(handleQueueComplete); queue.addOperation(new FirstOperation()); queue.addOperation(new SecondOperation()); queue.addOperation(new ThirdOperation()); queue.addOperation(new FourthOperation());
另外Spring ActionScript也封装好了一些通用的操作,列表如下:
Command(命令)
命令是需要延期执行的动作。这个概念跟Cairngorm中的Command很类似,它负责具体的逻辑处理,需要一定的机制来触发。在Cairngorm中是由FrontControler将事件映射到Command来触发Command的执行。而在Operation API中比较灵活,并没有规定由谁来触发Command,而很多情况下我们可以把它和Task结合起来使用,功能强大,后面会做介绍。Command的接口也比较简单:
public interface ICommand { function execute():*; }
继承此接口需要实现execute的方法。跟操作类似,我们也可以把若干命令集合起来使用,这里要使用CompositeCommand类。注意你可以定义执行的方式(并行或顺序执行):
var compositeCommand:CompositeCommand = new CompositeCommand(ComposeiteCommandKind.SEQUENCE); compositeCommand.addCommand(new FirstCommand()); compositeCommand.addCommand(new SecondCommand()); compositeCommand.addCommand(new ThirdCommand()); compositeCommand.addCommand(new FourthCommand()); compositeCommand.addCompleteListener(handleCompositeCommandComplete); compositeCommand.addErrorListener(handleCompositeCommandError); compositeCommand.execute();
我们通常不会直接调用一个操作,而是调用命令(操作一般放到命令或服务里调用),而为每一个操作都对应一个命令的类并不现实,这时我们可以使用GenericOperationCommand。
var genericOperationCommand = new genericOperationCommand(LoadModuleOperation,['module.swf']); genericOperationCommand.addCompleteHandler(operationCompleteHandler); genericOperationCommand.execute();
Service(服务)
服务的实现则完全跟我们的业务逻辑相关,我们首先需要定义接口,抽象出那些需要跟后端交互的方法。比如我们的应用中要实现用户信息操作的服务,则接口定义如下:
public interface IUserService { function createUser():IOperation; function updateUser(user:User):IOperation; function deleteUser(user:User):IOperation; }
服务的实现,这里选择继承RemoteObjectService来简化操作:
public class UserService extends RemoteObjectService implements IUserService { public function UserService(remoteObject:RemoteObject) { Assert.notNull(remoteObject,"remoteObject argument must not be null"); super(remoteObject); } public function createUser():IOperation { return call('createUser'); } public function updateUser(user:User):IOperation { return call('updateUser',user); } public function deleteUser(user:User):IOperation { return call('deleteUser',user); } }
然后我们可以在命令中调取服务,来做具体的逻辑判断:
public class CreateUserCommand extends AbstractOperation implements IAsyncCommand { private var _userService:IUserService; private var _applicationModel:IApplicationModel; public function CreateUserCommand(userService:IUserService, applicationModel:IApplicationModel) { Assert.notNull(userService,"userService argument must not be null"); Assert.notNull(applicationModel,"applicationModel argument must not be null"); _userService = userService; _applicationModel = applicationModel; } public function execute():* { var operation:IOperation = _userService.createUser(); operation.addCompleteListener(handleComplete); operation.addErrorListener(handleError); } protected function handleComplete(event:OperationEvent):void { _applicationModel.users.addItem(event.result as User); dispatchCompleteEvent(event.result); } protected function handleError(event:OperationEvent):void { dispatchErrorEvent(event.error); } }
Task(任务)
为了可以方便的批量执行Command,Spring ActionScript引入了Task的概念。一个Task是若干Command的集合,但不仅仅如此,Task允许你定义Command的执行顺序,甚至可以引入循环和判断。首先预览一下ITask这个接口:
public interface ITask extends ICommand, IOperation { function get parent():ITask; function set parent(value:ITask):void; function next(command:ICommand):ITask; function and(command:ICommand):ITask; function if_(condition:IConditionProvider=null, ifElseBlock:IIfElseBlock=null):IIfElseBlock; function else_():IIfElseBlock; function while_(condition:IConditionProvider=null, whileBlock:IWhileBlock=null):IWhileBlock; function exit():ITask; function end():ITask; }
Task类实现了这个接口,如前所述,我们可以定义Command的执行顺序,比如我们要并行执行,代码如下:
var task:Task = new Task().and(new FirstCommand()).and(new SecondCommand()).and(new ThirdCommand()).and(new FourthCommand()); task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); task.execute();
我们还可以使用next方法,含义是先执行前面的Command,等待执行完毕之后,再执行下一个Command。比如:
var task:Task = new Task().and(new FirstCommand()).and(new SecondCommand()).next(new ThirdCommand()).next(new FourthCommand()); task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); task.execute();
在Task里执行For循环:
var task:Task = new Task(); task.for_(10) .next(new FirstCommand()) .end(); task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); task.execute();
我们也可以使用If判断,条件是一个实现IConditionProvider接口的类:
public interface IConditionProvider { }
var task:Task = new Task(); task.if_(new ConditionProvider()) .next(new FirstCommand()) .else_() .next(new SecondCommand()) .end(); task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); task.execute();
还可以使用While循环:
var task:Task = new Task(); task.while_(new MyConditionProvider()) .next(new FirstCommand()) .end(); task.addEventListener(TaskEvent.TASK_COMPLETE, handleTaskComplete); task.execute();
下面我们看看如何在XML配置中使用Task,首先是命名空间的配置:
<objects xmlns="http://www.springactionscript.org/schema/objects" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://www.springactionscript.org/schema/task" xsi:schemaLocation=" <a href="http://www.springactionscript.org/schema/objects" title="http://www.springactionscript.org/schema/objects">http://www.springactionscript.org/schema/objects</a> <a href="http://www.springactionscript.org/schema/objects/spring-actionscript-objects-1.0.xsd<br /> " title="http://www.springactionscript.org/schema/objects/spring-actionscript-objects-1.0.xsd<br /> ">http://www.springactionscript.org/schema/objects/spring-actionscript-obj...</a> <a href="http://www.springactionscript.org/schema/task" title="http://www.springactionscript.org/schema/task">http://www.springactionscript.org/schema/task</a> <a href="http://www.springactionscript.org/schema/util/spring-actionscript-task-1.0.xsd"></p> <p>" title="http://www.springactionscript.org/schema/util/spring-actionscript-task-1.0.xsd"></p> <p>">http://www.springactionscript.org/schema/util/spring-actionscript-task-1...</a> <!-- further markup ommitted --> </objects>
要使用Task的命名空间,你需要为上下文添加TaskNamespaceHandler的类:
applicationContext.addNamespaceHandler(new TaskNamespaceHandler());
这样你就可以在XML配置中使用Task了,一个简单的Task配置如下:
<t:task id="testTask" scope="prototype"> <t:and> <object id="command1" scope="prototype" class="classes.commands.FirstCommand"/> </t:and> <t:and> <object id="command2" scope="prototype" class="classes.commands.SecondCommand"/> </t:and> <t:next> <object id="command3" scope="prototype" class="classes.commands.ThirdCommand"/> </t:next> <t:next> <object id="command3" scope="prototype" class="classes.commands.FourthCommand"/> </t:next> </t:task>
你可以把Command单独配置,修改如下:
<object id="command1" scope="prototype" class="classes.commands.FirstCommand"/> <object id="command2" scope="prototype" class="classes.commands.SecondCommand"/> <object id="command3" scope="prototype" class="classes.commands.ThirdCommand"/> <object id="command3" scope="prototype" class="classes.commands.FourthCommand"/> <t:task id="testTask" scope="prototype"> <t:and command="command1"/> <t:and command="command2"/> <t:next command="command3"/> <t:next command="command4"/> </t:task>
加入判断:
<object id="command1" scope="prototype" class="classes.commands.FirstCommand"/> <object id="command2" scope="prototype" class="classes.commands.SecondCommand"/> <object id="myCondition" scope="prototype" class="classes.condition.MyConditionProvider"/> <t:task id="testTask" scope="prototype"> <t:if condition="myCondition"> <t:next command="command1"/> <t:else/> <t:next command="command2"/> </t:if> </t:task>
参考网页:
http://www.springactionscript.org/docs/reference/html/the_operation_api.html
在下一篇文章中我们将使用Operation API完成一个实例,敬请关注.

.gif)
.gif)




.gif)
发表新评论