中央管理的理念是使用一个远程对象管理器来控制Flex与后端的通讯。其构建体系如下图所示
图中每一个UI组件都将调用一个服务(Service),服务类将调用中央管理器(Central Manager),中央管理器类将调用服务器端的解决方案。而图中全局对象管理器(Global Object Manager)将用来在UI之间传递数据。
现在来看看简单密友列表应用的实现。
首先是LoginView.xml
<?xml version=”1.0″ encoding=”utf-8″?> <mx:Panel xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” width=”300″ height=”200″ horizontalAlign=”center” verticalAlign=”middle” title=”Flex Central Manager Login”> <mx:Script> <![CDATA[ import com.ny.flex.centralManagement.service.LoginService; import mx.validators.Validator; import mx.containers.ViewStack; import mx.rpc.events.ResultEvent; private function login():void{ if(Validator.validateAll(validators).length == 0){ LoginService.getInstance().login(username.text,password.text); } } ]]> </mx:Script> <!– Validators–> <mx:Array id=”validators”> <mx:StringValidator id=”userNameValidator” source=”{username}” property=”text” required=”true”/> <mx:StringValidator id=”passwordValidator” source=”{password}” property=”text” required=”true” /> </mx:Array> <mx:Form id=”loginForm” x=”0″ y=”0″> <mx:FormItem label=”Username:” > <mx:TextInput id=”username” /> </mx:FormItem> <mx:FormItem label=”Password:” > <mx:TextInput id=”password” displayAsPassword=”true” /> </mx:FormItem> <mx:FormItem direction=”horizontal” verticalGap=”15″ paddingTop=”5″ width=”170″> <mx:Button id=”loginBtn” label=”Login” click=”login()”/> </mx:FormItem> </mx:Form> </mx:Panel>
其功能的核心是:
LoginService.getInstance().login(username.text,password.text);
它的作用是有效的分离了商务逻辑层和视图组件。在此服务类程序不需支持任何状态,因此我们保持其单件模式(singleton)。
LoginService类文件如下:
import com.ny.flex.centralManagement.event.DataManagerResultEvent; import com.ny.flex.centralManagement.manager.GlobalObjectManager; import com.ny.flex.centralManagement.manager.RemoteObjectManager; public class LoginService { public var roManager:RemoteObjectManager = null; public var gom:GlobalObjectManager = GlobalObjectManager.getInstance(); private static var _instance:LoginService =null; public static function getInstance():LoginService{ if(_instance == null){ _instance = new LoginService(new PrivateClass) } return _instance; } public function LoginService(privateclass:PrivateClass) { if(LoginService._instance == null){ LoginService._instance = this; } } public function login(userName:String,password:String):void{ roManager = RemoteObjectManager.getRemoteObjectManager(”flexmvcRO”); roManager.addEventListener(”getLoginUser”,loginHandler); var params:Array = new Array(userName,password); roManager.makeRemoteCall(”getLoginUserName”,”getLoginUser”,params); } private function loginHandler(event:DataManagerResultEvent):void { var userName:String = event.result as String; if(userName){ gom.loginUserName = userName; gom.viewStackSelectedIndex=1; } } }
代码中有两个特别的对象:
RemoteObjectManager
GlobalObjectManager
RemoteObjectManager是一个单件的类,用来实现中央管理所有的远程对象通讯。原始的代码来自于Jeff Tapper的博客:
Creating a Remote Object DataManager in ActionScript 3.0 for Flex 2.0
RemoteObjectManager.as:
package com.ny.flex.centralManagement.manager { import com.ny.flex.centralManagement.event.DataManagerResultEvent; import flash.events.EventDispatcher; import mx.core.Application; import mx.resources.ResourceManager; import mx.rpc.AbstractOperation; import mx.rpc.AsyncToken; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.remoting.mxml.RemoteObject; public class RemoteObjectManager extends EventDispatcher { public var ro:RemoteObject; private var eventName:String; private static var instanceMap:Object = new Object(); public function RemoteObjectManager(pri:PrivateClass,dest:String){ this.ro = new RemoteObject(); ro.destination = dest; } public static function getRemoteObjectManager(dest:String):RemoteObjectManager{ if(RemoteObjectManager.instanceMap[dest] == null){ RemoteObjectManager.instanceMap[dest] = new RemoteObjectManager(new PrivateClass(),dest); } var dm:RemoteObjectManager= RemoteObjectManager.instanceMap[dest]; return dm; } public function makeRemoteCall(methodName:String,eventName:String,args:Array=null):void{ this.eventName = eventName; var op:mx.rpc.AbstractOperation = ro[methodName]; ro.addEventListener("result", doResults); ro.addEventListener("fault", doFault); var token:AsyncToken = null; if(args && args.length >0){ token = op.send.apply(null,args); } else { token = op.send(); } token.eventName = eventName; } private function doResults(event:ResultEvent):void{ var e:DataManagerResultEvent = new DataManagerResultEvent(event.token.eventName, event.result); this.dispatchEvent(e); } private function doFault(fault:FaultEvent):void{ this.dispatchEvent(fault); } public override function toString():String{ return "RemoteObjectDataManager"; } } } /** PrivateClass is used to make DataManager constructor private */ class PrivateClass{ public function PrivateClass() {} }
“GlobalObjectManager”用来在UI之间传递信息,例如,我们使用ViewStack的selectedIndex来决定显示ViewStack中的哪一个视图,则使用全局对象viewStackSelectedIndex ,其代码如下面的黑体部分:
<?xml version=”1.0″ encoding=”utf-8″?> <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml“ xmlns:views=”com.ny.flex.centralManagement.views.*” layout=”absolute” width=”100%” height=”100%”> <mx:Script> <![CDATA[ import mx.binding.utils.BindingUtils; import com.ny.flex.centralManagement.manager.GlobalObjectManager; [Bindable] public var gom:GlobalObjectManager=GlobalObjectManager.getInstance(); ]]> </mx:Script> <mx:HBox horizontalAlign=”center” verticalAlign=”top” width=”100%” height=”100%” y=”0″ x=”0″> <mx:ViewStack id=”viewStack” resizeToContent=”true” selectedIndex=”{gom.viewStackSelectedIndex}” > <views:LoginView /> <views:BuddyListView/> </mx:ViewStack> </mx:HBox> </mx:Application>
再回头看看在
LoginService 代码中的loginHandler 方法,在此 viewStackSelectedIndex 全局对象被更新。LoginService
代码中的loginHandler 方法,在此 viewStackSelectedIndex 全局对象被更新。
private function loginHandler(event:DataManagerResultEvent):void { var userName:String = event.result as String; if(userName){ gom.loginUserName = userName; gom.viewStackSelectedIndex=1; } }
[Bindable]元标签使得其值的改变立刻生效。
BuddyList.mxml代码:
<?xml version=”1.0″ encoding=”utf-8″?> <mx:Panel xmlns:mx=”http://www.adobe.com/2006/mxml” title=”Buddy List of {gom.loginUserName}” creationComplete=”init()” width=”500″ height=”320″> <mx:Script> <![CDATA[ import com.ny.flex.centralManagement.service.BuddyService; import com.ny.flex.centralManagement.manager.GlobalObjectManager; import mx.collections.ArrayCollection; import mx.rpc.events.ResultEvent; [Bindable] public var gom:GlobalObjectManager = GlobalObjectManager.getInstance(); private function init():void{ BuddyService.getInstance().getBuddyList(); } ]]> </mx:Script> <mx:DataGrid id=”buddyList” dataProvider=”{gom.mybuddyList}” borderStyle=”none” width=”100%” height=”100%” > <mx:columns> <mx:DataGridColumn dataField=”firstName” headerText=”First Name”/> <mx:DataGridColumn dataField=”lastName” headerText=”Last Name”/> </mx:columns> </mx:DataGrid> </mx:Panel>
BuddyService是另一个服务类代码用来和远程对象通讯。
这是最符合本人喜好的Flex程序的框架结构。它的优点是非常的清晰,没有累赘的发送和监听事件的工作,并且代码非常容易维护。遗憾的是,在此还没有获得足够的理论支持这一框架理论。
再来看看MVC框架的代表:MVC-Cairngorm。