虽然前面讲述的类型依赖注入已经允许一定程度的解耦,但有时程序某些部分需要更松散的耦合,让应用程序的一部分通过消息进行通信,发送方和接收方不须了解彼此。Flash/Flex事件机制很强大。从发送方来看,它实现了完全解耦。需要发送的消息类或组件不需要知道谁将侦听消息,所有要做的就是派发事件。但从接收方来看,它不是完全解耦。在Flash/Flex中,你必须通过监听事件侦听器来捕获消息,而事件侦听器必须是可调度该事件的对象的类/组件的实例。Flash事件有冒泡功能,可以通过对派发事件的视图对象父容器添加事件侦听器来捕获消息。也说是说,Flash/Flex事件可以通过视图层次结构并在其他地方捕获消息,这意味着接收时它还是提供了一些解耦,但事件侦听器不得不依附组成视图层次结构的实例。你可以通过应用对象根来解耦,但这也意味着你不能有更多的特定范围。所以说Flash和Flex事件并没有实现消息总线和完全解耦,这正是引入Parsley事件消息的根本原因。
Parsley有一个通用的消息传递框架,该框架允许你用一个完全分离的方式交换对象之间的消息。你不需要对任何类进行扩展,也不需要为特定的目标对象附加、绑定、指定任何事件侦听器。Parsley事件消息解耦不仅仅意味着发送方和接收方不需要知道彼此,发送和接收对象也完全对框架本身解耦也是同样重要的。你可以在不同的上下文中重用它们,你可能想使用一个不同的框架或没有框架。例如,你可能想以编程方式分派和接收实例来进行单元测试,没有初始化一个应用程序框架的额外的负担。一些现有的Flex MVC框架经常提倡一个特定的结构、使用特定的模式甚至提供控制器、模型和视图部分具体的基类。Parsley不强制要求使用特定的风格,我们可以完全自由地设计应用程序体系结构。通常情况下,简单使用[MessageDispatcher]
元数据标签来注入一个消息分发器函数,Parsley调用它派发一个消息实例并按路线发送给注册的接收者。接收对象可以声明特定消息类型的关联,用一些元数据标签比如像[MessageHandler]
。此外,仍可以使用Flash和Flex的自定义事件,但这不是必须的。
派发消息
顾名思义,Parsley事件消息表明了以下两种派发消息的方式。
使用消息分发器函数
有时候你不想为你的应用程序消息使用事件。比如说被Parsley托管的应用程序事件不能“冒泡”,stopPropagation在Parsley消息处理序列中不会有任何效果,避免消息接收器可以通过event.target得到消息分发器。在这些情况下Parsley可以使用任何类作为应用程序消息,无论它是否继承于Flash事件基类。如本实例SharedModel.as:
package model
{
public class SharedModel
{
private var _message:String;
[Bindable]
public function get message():String
{
return "Hello, " + _message;
}
public function set message(value:String):void
{
_message = value;
}
}
}
接着声明一个Function类型属性,用[MessageDispatcher]
元数据标签表明Parsley在对象创建的时候注入一个消息分发器函数。然后你可以简单地通过这个分发器函数传递任何类型的对象。如Parsley-Messaging工程中SenderView.mxml的代码片段:
[MessageDispatcher]
public var dispatcher:Function;
private function clickHandler(event:MouseEvent):void
{
sharedModel.message = ti.text;
dispatcher(sharedModel);
}
使用托管事件
如果需要使用已有Flash/Flex自定义事件,可以用托管事件来派发消息。首先用普通的[Event]
标签声明你的类要分派的事件,再使用[ManagedEvents]
标签告诉Parsley哪些声明的事件应该被托管,这样他们可用于框架的消息接收器配置。如Parsley-Event工程中ReceiverView.mxml的代码片段:
<fx:Metadata>
[Event(name="share", type="events.SharedEvent")]
[ManagedEvents("share")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.core.FlexGlobals;
import events.SharedEvent;
private function clickHandler(event:MouseEvent):void
{
dispatchEvent(new SharedEvent(SharedEvent.SHARE, ti.text));
}
]]>
</fx:Script>
接受消息
无论使用哪种方式派发消息,接收消息的方式基本上是相同的。最常用的是使用消息处理元数据标签[messagehandler]
,只需把它放置在想调用方法声明上面。如Parsley-Messaging工程中ReceiverView.mxml的代码片段:
[MessageHandler]
public function handleMessage(sharedModel:SharedModel):void
{
lbl.text = sharedModel.message;
}
当侦听到匹配的SharedModel类型消息时,handleMessage方法将被调用。略微不同的是,如果使用托管事件,应该匹配SharedEvent事件类型。如Parsley-Event工程中ReceiverView.mxml的代码片段:
[MessageHandler]
public function handleMessage(event:SharedEvent):void
{
lbl.text = event.message;
}
参考源码
事件消息是一种特殊的依赖注入,它通过事件消息元数据标签来管理特定类型的对象,因此不需要定义配置文件来托管消息对象,但我们至少需要添加ContextBuilder标签创建一个空的上下文。另外由于使用的显式视图装配的方式,因此Configure标签不可少,表明该视图由Parsley管理。
注意要点
- 与典型的依赖注入一样,在组件的生命周期事件中派发消息往往会失败,因为这些事件一般都在对象的注入完成之前发生。
- 事件一旦使用Parsley托管,就不再可以“冒泡”。
- 如果你在不同的场景或应用程序状态发送相同的消息类型,在这种情况下你可以用自定义选择器来改进选择过程。
- 消息处理还包括消息绑定(MessageBindings)和拦截消息(Intercepting Messages )。
- 推荐在一个上下文的应用程序和在多上下文的根上下文应用程序使用全局作用域。子上下文建议切换到本地作为默认的设置。
- 要更多了解Parsley依赖注入,请查看Parsley文档相应部分。
评论 (0)