`
houwei
  • 浏览: 61537 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Flex 开发架构(二): 中央管理-Flex Central Managerment

    博客分类:
  • Flex
阅读更多

 

Flex Chaos-All-in-one这一节中所提到的,在大型项目中,将所有的代码放在一起并非明智之举,确切的讲:正确的方法是将商业逻辑层与UI层分离开来。

 

 

中央管理的理念是使用一个远程对象管理器来控制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之间传递信息,例如,我们使用ViewStackselectedIndex来决定显示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

 

 

分享到:
评论
8 楼 huangxin5257 2010-02-11  
tj19832 写道
单例的GlobalObjectManager用于在UI之间传递数据,我觉得有点欠妥。
尤其当对象之间的关系非常复杂的时候。

Flex中不恰当的使用单例,可能是为了解决内存问题。
7 楼 bojay 2009-08-25  
       
引用
[flash=200,200][/flash]
[img][/img]
引用
[u][/u][i][/i][b][/b][/color][color=red][size=x-small][/size][align=center][/align]o ps:    
6 楼 jiorry 2009-02-14  
flex开发大型框架的难点在于解决 内存释放的问题。
5 楼 liuwenquan 2008-12-05  
找到原因,在RemoteObject中没有设置endpoint属性
4 楼 liuwenquan 2008-12-04  
houwei兄,这段代码不能login.
什么原因?没有其他兄弟测试过?
token = op.send.apply(null,args);
执行后,发现token的信息中destination=""
3 楼 yangjiehuan 2008-11-04  
谢谢分享。同时也谢谢Jeff Tapper。一直苦恼于框架的问题。当你的一个页面中有超过1000行代码的时候就不得不思考原因了。。。之前尝试小框架puremvc,虽说只是小框架,但和实际开发格格不入。下个case就用这个框架了。
2 楼 houwei 2008-08-06  
如果是webapp, 不会是问题, 因为flex在server端是httpsession base 的。
1 楼 tj19832 2008-08-05  
单例的GlobalObjectManager用于在UI之间传递数据,我觉得有点欠妥。
尤其当对象之间的关系非常复杂的时候。

相关推荐

Global site tag (gtag.js) - Google Analytics