Parsley不同于其他一些Flex和Flash MVC框架,因为它不提供非常明确的支持各种不同的MVC架构。我们的主要目标是允许设计一个完全解耦架构,这是一个副作用。在某种意义上,解耦不仅是应用程序互相解耦的,而且也脱离了框架本身。例如为控制器或者中介者提供框架的基类,应用程序必须继承,如果你想支持一个解耦架构,这是一个坏主意。
因此Parsley的消息传递机制我们在 6 消息传递 是非常通用的。它不假定一个特定的编程风格或者架构模式。不过Parsley仍然跟大多数MVC框架属于同一类,因为消息传递框架很容易地用这样一种方式使用:有助于构建一个基于MVC体系结构模式的应用程序。
下面的图显示了一个示例在Parsley MVC应用程序的上下文中的一个特定的用例(用户添加条目到购物车)的流。
用图片中编号的顺序解释这个图:
l 1: 用户单击“Add to cart”按钮。Flex将产生一个低等级的UI事件。组件中的事件处理程序会调用表示层模型实例(通常是注入到视图的)的方法复制处理视图和控制器之间的通信。
l 2: 该模型创建一个application消息,可能收集任何更深视图的信息并且封装此信息到消息中。这个消息将通过Parsleys MessageRouter派发。
l 3: MessageRouter将处理任何为这个消息类型(通常在方法或者属性上使用元数据标签,或者在MXML或XML)注册的MessageHandlers或Commands 。
l 4: 该命令将调用远程服务方法(服务通常被注入)。异步操作将被框架管理,以避免一些常见的管道代码。无论是命令和应用程序的其他部分必须显式地添加一个结果处理程序为远程调用返回的AsyncToken。
l 5: 框架接收结果。这是第一次返回到命令实例本身,如果它包含了一个结果处理程序。但是这纯粹是可选的。
l 6: 命令中的结果处理程序可能会修改或者缓存这个对象在它传递到其他处理器之前。
l 7: 下一步框架将调用应用程序中任何其他注册的结果处理程序。在本例中CartPM包含一个结果处理程序,现在将被调用来更新模型实例的内部状态。
l 8: 视图刷新,通常通过绑定到表示层模型的属性。
上面的例子中,很多核心元素将被设置和连接在一个Parsley上下文包括视图,如9 动态视图装配 描述。这通常包括所有的控制器行为,他们的依赖比如远程服务,在MessageRouter中为特定的消息注册。
如果你认为这个图看起来像过度设计,它只是作为一个完整的MVC架构的一个大而复杂的应用程序的一个例子。在小的、简单的应用程序,你当然可以简化设计上面给出的例子。
最后我们会选出呈现在上图的其中一块,展示如何实现和配置这样的应用程序部分:
package com.bookstore.actions {
import mx.rpc.AsyncToken;
import mx.rpc.Fault;
import mx.rpc.remoting.RemoteObject;
import com.bookstore.messages.AddToCartMessage;
import com.bookstore.services.CartService;
import com.bookstore.model.LineItem;
public class AddToCartCommand {
[Inject(id="cartService")]
public var cartService:RemoteObject;
public function execute (message: AddToCartMessage): AsyncToken {
return cartService.addItem(message.item);
}
public function result (item: LineItem): void {
/* modify or cache the result */
}
public function error (fault: Fault): void {
/* handle fault */
}
}
}
这是你如何在Parsley配置类(本例中是MXML)映射这样一个命令到消息:
<parsley:MapCommand type="{AddToCartCommand}" />
我们现在详细检查这个类的各个部分。首先是执行该命令的方法:
public function execute (event: AddToCartMessage) : AsyncToken {
该方法参数告诉框架,我们对AddToCartMessage感兴趣。MessageHandler选择发生基于消息类型,所以在一个大而复杂的应用程序,不会遇到在整个系统中必须维护唯一事件类型常量的问题。
在该方法的主体我们使用注入的CartService:
[Inject(id="cartService")]
public var cartService:RemoteObject;
在这个示例中,我们使用RemoteObject。 我们通常更喜欢使用注入的类型,但这并不适用于只能通过id区分的RemoteObjects,详细信息请参阅14 远程访问。
最后是结果和错误处理程序:
public function result (item:LineItem) : void {
public function error (fault:Fault) : void {
我们遵循一种命名约定,所以我们可以完全避免任何元数据配置。基于该方法的名字框架知道哪些方法执行命令和处理结果或错误。结果和错误处理程序都是可选的。