最近,我公司计划将技术框架由J2EE+ORACLE迁移到FLEX+J2EE+ORACLE,RIA是大势所趋,用户体验越来越重要。公司在FLEX前端选择了cairngorm微架构,用于处理客户端交互与服务器远程通讯。如何发挥架构优点,避免架构缺点成为一个关键问题。本文的主要目标就是针对cairngorm微架构过于依赖Model Locator的缺点对架构进行调整和扩展,同时还简化了Cairngorm框架的工作流程。
一、Cairngorm框架的工作流程:
1. 前端控制器(FrontController)监听用户行为
前端控制品是Cairngorm事件的唯一监听者,但其不并做任何操作,只是集中注册并管理事件(Event)与命今(Command)的映射关系。
2. 命令(Commands)执行所有用户操作
前端控制品(FrontController)监听到事件与命令有匹配时,便告诉命令(Commmands)调用execute()方法处理事件。
3. 服务器端业务逻辑委托给Business Delegate
当命令(Commands)执行时,它只是关心是否获取到数据,而并不关心获取到什么具体数据。因为经常需要从服务器端获取数据,此时命令(Commands)更喜欢把它委托给其它类去操作。所以需要处理服务器端业务逻辑的时候,你都可以委托给命令(Commands)可以调用的Business Delegate类去处理。
4. Business Delegate在Service Locator中寻找RPC Services
Business Delegate给命令(Commands)和RPC Services提供一个无缝接口。Business Delegate通过查找和匹配 PRC Services的名称来调用services并返回结果给命令(Commands)。命令(Commands)要从Business Delegate获取返回结果数据必须通过IResponder接口(mx.rpc.IResponder),只有这样Business Delegate才知道命命令(Commands)有onResult()和onFault()来处理返回的数据。
5. 把数据存储为Value Objecs
强烈推荐把数据存储为Value Objects。
6. 在Model Locator保存状态并且让Model通知View
Model Locator是一个保存应用程序全部状态和包含Value Objects的地方。当应用程序状态改变时,Moel Locator 通过Data Binding方式来通知View改变。
Cairngorm框架的工作流程存在如下主要问题:
二、Cairngorm框架的工作流程问题分析与解决办法
该工作流程在实践中的一个主要问题是Model Locator全局单例类,该设计将应用中的所有数据集中于Model Locator,有很多优点,也导致了众多问题出现,如:
1. 灵活性低:相当于一个新的GOD类,知道应用中所有信息。而复杂应用中的众多数据难以被一个GOD类包含。框架对Model Locator存在严重依赖,未来的变更将变得困难。
2. 问题测试困难:Model Locator对所有Commands公开,当出现数据问题时,难以检查问题原因。
3. 数据校验困难:View通过绑定刷新显示,难以对数据进行检查和校验,从而也不能更友好的进行用户提示。View不能直接得到数据,不方便对数据进行检查和其他处理。
框架扩展方案主要有如下2种:
1. 在命令(Commands)获取返回结果数据,分发数据变更事件。UI对象(View)监控数据变更事件,更新View。
a) 原理:本方案直接利用了FLEX的事件处理机制,显得比较直观。
b) 优点:不再依赖Model Locator。View监控解决了数据校验问题。
c) 缺点:增加事件嵌套层次,增加了复杂度。命令(Commands)的重用变得困难,因为一旦重用就存在多个View监听同一事件的问题,出现事件交叉。问题测试困难没有彻底解决。
2. UI对象(View)作为事件的发起者,将View更新的方法变成Responder,从事件传递给命令(Commands)。命令(Commands)获取返回结果数据后,调用View更新的方法更新View。在同一个Application中同时启动多个View实例不会出现数据交叉影响的情况。
a) 原理:Responder,利用了函数式编程。View应该知道当数据变化时如何更新自己。
b) 优点:无数据交叉和事件交叉。不依赖Model Locator。解决了数据校验问题。本方案是变化小、影响小、效果好的解决方案。
二、扩展后的Cairngorm框架
扩展后的框架图(中间一层为原Cairngorm框架中的部分类)
1. Event的扩展和调用
a) 事件Event继承自ViewCallbackEvent
b) 在View中定义回调方法callbacks
c) 在View中根据用户请求分发事件ViewCallbackEvent
2. Command的扩展
a) Command继承自ViewCallbackCommand
b) Command获得事件Event中的callbacks
c) Command执行Delegate,从服务器获取数据
d) 获取数据后,调用callbacks更新事件对应的View
三、示例代码
1. ViewCallbackEvent实现
public class ViewCallbackEvent extends CairngormEvent
{
private var _callbacks:CallBacks;//View的callback异步调用
public function ViewCallbackEvent(EVENT_ID:String,callbacks:CallBacks)
{
super(EVENT_ID);
this._callbacks = callbacks;
}
public function get callbacks():CallBacks{
return _callbacks;
}
}
2. event调用示例
var callbacks:CallBacks = new CallBacks(resultDate,faultHandler);
var event:CurrentServerTimeEvent = new CurrentServerTimeEvent(callbacks,"today","yyyy-MM-dd HH:mm:ss");
event.dispatch();
3. ViewCallbackCommand 实现
public class ViewCallbackCommand implements ICommand, IResponder
{
private var callbacks:CallBacks;
/**
* 默认的指定函数,需调用
*
**/
public function execute(event:CairngormEvent):void
{
var e: ViewCallbackEvent = event as ViewCallbackEvent;
this.callbacks = e.callbacks;
}
/**
* 默认的成功返回函数,如果没有处理,可以不重载
*
**/
public function result(data:Object):void
{
if(callbacks!=null){
callbacks.result(data);
}
}
/**
* 默认的返回函数,自动调用外部的返回
**/
public function fault(event:Object):void
{
var faultEvt:FaultEvent = event as FaultEvent;
//Error Management goes here
trace(faultEvt.fault.faultString);
if(callbacks!=null){
callbacks.fault(event);
}
}
}
4. Command示例
public class CurrentServerTimeCommand extends ViewCallbackCommand
{
override public function execute(event:CairngormEvent):void
{
//此句必须
super.execute(event);
// cast
var e:CurrentServerTimeEvent =event as CurrentServerTimeEvent;
var delegate :CoreDelegate = new CoreDelegate( this );
delegate.currentServerTime(e.defaults,e.format);
}
override public function result(data:Object):void
{
//如果要重写,此句必须
super.result(data);
//此处可以写自己的处理方法,可以使用Model Locator
var returnedData:String = data.result as String;
ModelLocator.getInstance().currentServerTime = returnedData;
}
}
如果不熟悉cairngorm框架,请参考:
http://www.adobe.com/devnet/flex/articles/cairngorm_pt1.html官方框架介绍
http://hideto.javaeye.com/blog/109149介绍Cairngorm
http://blog.csdn.net/yangyawen/archive/2009/03/04/3955968.aspx flex cairngorm MVC 介绍