Mate-基于标签的框架

Mate 将会成为Flex领域的另一个热点。它使用设置(configuration)来调用Service,处理结果,同样也使用设置文件来更新绑定对象(Bindable object)。从某个角度来说:MateFlex领域的“springframework”。

 

Mate有两个架构层面的图表。一个是来自Yakov Fain of Farata Systems,另一个来自ASFusion。我更喜欢后者,其构架图如下:

 

http://mate.asfusion.com/assets/content/diagrams/two_way_view_injection.png

 

来看看用Mate的编程方式来建立buddyList应用程序。

1,建立Mate的核心组件:EventMap

EventMapMate的心脏,它黏着了所有的组件和控件。其代码如下:

BuddyListEventMap.mxml:

 

Xml代码  收藏代码
  1. <?xml version=”1.0″ encoding=”utf-8″?>  
  2.     
  3. <EventMap xmlns=”http://mate.asfusion.com/”   
  4.                              xmlns:mx=http://www.adobe.com/2006/mxml>  
  5.   
  6. </EventMap>  
<?xml version=”1.0″ encoding=”utf-8″?>    <EventMap xmlns=”http://mate.asfusion.com/”                               xmlns:mx=http://www.adobe.com/2006/mxml>  </EventMap> 

 

 

 

 

 

 

其它内容稍后再填写,现在我们需要告诉主程序(Main Application)初始化EventMap

主程序 Flex_Mate.mxml:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <mx:Application  xmlns:map="com.ny.flex.mate.map.*" xmlns:views="com.ny.flex.mate.views.*" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">  
  3. <mx:Script>  
  4.     <![CDATA[ 
  5.         [Bindable] 
  6.         public var viewStackSelectedIndex :int = 0; 
  7.     ]]>  
  8. </mx:Script>  
  9. <span style="color: rgb(255, 102, 0);"><strong><em><map:BuddyListEventMap/></em></strong></span>  
  10.     <mx:HBox  horizontalAlign="center" verticalAlign="top"  width="100%" height="100%" y="0" x="0">  
  11.     <mx:ViewStack id="viewStack"  resizeToContent="true" selectedIndex="{viewStackSelectedIndex}" >  
  12.         <views:LoginView  />  
  13.         <views:BuddyListView/>  
  14.     </mx:ViewStack>  
  15.     </mx:HBox>  
  16. </mx:Application>  
<?xml version="1.0" encoding="utf-8"?> <mx:Application  xmlns:map="com.ny.flex.mate.map.*" xmlns:views="com.ny.flex.mate.views.*" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> 	<![CDATA[ 		[Bindable] 		public var viewStackSelectedIndex :int = 0; 	]]> </mx:Script> <map:BuddyListEventMap/>     <mx:HBox  horizontalAlign="center" verticalAlign="top"  width="100%" height="100%" y="0" x="0">     <mx:ViewStack id="viewStack"  resizeToContent="true" selectedIndex="{viewStackSelectedIndex}" >         <views:LoginView  />         <views:BuddyListView/>     </mx:ViewStack>     </mx:HBox> </mx:Application> 

 

 

 

 

2. 建立LoginView :

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="300" height="200" horizontalAlign="center" verticalAlign="middle" title="Flex Cirngorm Login">  
  3.  <mx:Script>  
  4.     <![CDATA[ 
  5.         import com.ny.flex.mate.event.LoginEvent; 
  6.         import com.ny.flex.mate.vo.User; 
  7.         import mx.validators.Validator; 
  8.         private function login():void{ 
  9.             if(Validator.validateAll(validators).length == 0){ 
  10.                 var loginUser:User = new User(); 
  11.                 loginUser.userName=username.text; 
  12.                 loginUser.password=password.text; 
  13.                 <span style="color: rgb(255, 102, 0);"><strong><em>var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN); 
  14.                 loginEvent.loginUser = loginUser; 
  15.                 dispatchEvent(loginEvent);</em></strong></span> 
  16.             }    
  17.         } 
  18.     ]]>  
  19. </mx:Script>  
  20.   
  21.  <!--  Validators-->  
  22.  <mx:Array id="validators">  
  23.     <mx:StringValidator  id="userNameValidator" source="{username}"  property="text"  required="true"/>  
  24.     <mx:StringValidator  id="passwordValidator" source="{password}"  property="text" required="true" />  
  25.  </mx:Array>      
  26.   
  27.   
  28. <mx:Form id="loginForm" x="0" y="0">  
  29.           <mx:FormItem label="Username:" >  
  30.                <mx:TextInput id="username" />  
  31.            </mx:FormItem>  
  32.            <mx:FormItem label="Password:" >  
  33.                <mx:TextInput id="password" displayAsPassword="true" />  
  34.            </mx:FormItem>  
  35.            <mx:FormItem direction="horizontal" verticalGap="15" paddingTop="5" width="170">  
  36.                <mx:Button id="loginBtn" label="Login" click="login()"/>  
  37.            </mx:FormItem>  
  38.     </mx:Form>  
  39.       
  40. </mx:Panel>  
<?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 Cirngorm Login">  <mx:Script> 	<![CDATA[ 		import com.ny.flex.mate.event.LoginEvent; 		import com.ny.flex.mate.vo.User; 		import mx.validators.Validator; 		private function login():void{ 			if(Validator.validateAll(validators).length == 0){ 				var loginUser:User = new User(); 				loginUser.userName=username.text; 				loginUser.password=password.text; 				var loginEvent:LoginEvent = new LoginEvent(LoginEvent.LOGIN); 				loginEvent.loginUser = loginUser; 				dispatchEvent(loginEvent); 			}    		} 	]]> </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> 

 

 

从上面可以看出在方法login()中发送(dispatch)了LoginEvent, 来看看LoginEvent代码:

Xml代码  收藏代码
  1. package com.ny.flex.mate.event  
  2. {  
  3.     import com.ny.flex.mate.vo.User;  
  4.       
  5.     import flash.events.Event;  
  6.   
  7.     public class LoginEvent extends Event  
  8.     {  
  9.         public static const LOGIN:String = "login";  
  10.         public var  loginUser:User;  
  11.         public function LoginEvent(type:String, <span style="color: rgb(255, 102, 0);"><strong><em>bubbles:Boolean=true</em></strong></span>, cancelable:Boolean=false)  
  12.         {  
  13.             super(type, bubbles, cancelable);  
  14.         }  
  15.           
  16.     }  
  17. }  
package com.ny.flex.mate.event { 	import com.ny.flex.mate.vo.User; 	 	import flash.events.Event;  	public class LoginEvent extends Event 	{ 		public static const LOGIN:String = "login"; 		public var  loginUser:User; 		public function LoginEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false) 		{ 			super(type, bubbles, cancelable); 		} 		 	} }

 

在代码中“bubbles”属性必须为“true”,以使得上层的组件(EventMap)可以处理它。

Mate的魔法完全存在于EventMap中,LoginEvent在这里被标签化处理:

Xml代码  收藏代码
  1. …..  
  2.    
  3. <EventHandlers type=”{LoginEvent.LOGIN}“>  
  4.      <RemoteObjectInvoker destination=”flexmvcRO”   
  5.                                                 method=”authenticate”   
  6.                                                 arguments=”{event.loginUser}“>  
  7.    
  8.          <resultHandlers>  
  9.                <MethodInvoker generator=”{<span style="color: rgb(255, 102, 0);"><strong><em>LoginService</em></strong></span>}”   
  10.                                          method=”<span style="color: rgb(255, 0, 0);"><strong><em>onResult_Authenticate</em></strong></span>”   
  11.                                                     arguments=”{<span style="color: rgb(128, 0, 0);"><strong><em>resultObject</em></strong></span>}“/>  
  12.         </resultHandlers>  
  13.     </RemoteObjectInvoker>  
  14.  </EventHandlers>  
  15. ……  
…..   <EventHandlers type=”{LoginEvent.LOGIN}“>      <RemoteObjectInvoker destination=”flexmvcRO”                                                  method=”authenticate”                                                  arguments=”{event.loginUser}“>            <resultHandlers>                <MethodInvoker generator=”{LoginService}”                                           method=”onResult_Authenticate”                                                      arguments=”{resultObject}“/>         </resultHandlers>     </RemoteObjectInvoker>  </EventHandlers> …… 

  

 

EvevntHandler代码中,用户可以定义service函数(RemoteObjectInvoker),同时也定义了结果处理的类、方法和参数。

来看看 LoginService.as代码::

 

 

Xml代码  收藏代码
  1. package com.ny.flex.mate.service  
  2. {  
  3.     import com.ny.flex.mate.vo.User;  
  4.       
  5.     public class <span style="color: rgb(255, 102, 0);"><strong><em>LoginService</em></strong></span>  
  6.     {  
  7.         [Bindable]  
  8.         public var authUserName:String;  
  9.         [Bindable]  
  10.         public var viewStackSelectedIndex:int ;  
  11.   
  12.         public function  <span style="color: rgb(255, 0, 0);"><strong><em>onResult_Authenticate</em></strong></span>(<span style="color: rgb(128, 0, 0);"><strong><em>user:User</em></strong></span>):void{  
  13.             authUserName = user.userName;  
  14.             viewStackSelectedIndex = 1;  
  15.         }  
  16.           
  17.     }  
  18. }  
package com.ny.flex.mate.service { 	import com.ny.flex.mate.vo.User; 	 	public class LoginService 	{ 		[Bindable] 		public var authUserName:String; 		[Bindable] 		public var viewStackSelectedIndex:int ;  		public function  onResult_Authenticate(user:User):void{ 			authUserName = user.userName; 			viewStackSelectedIndex = 1; 		} 		 	} }

 

Service类处理结果,返回绑定的对象。然后我们就需要更新目标视窗。

Mate另一个闪光点就是注射(Injecting)可绑定的对象到目标视窗!用户只需要在EventMap类中增加另一个标签Injector。(Coolest 部分):

 

Xml代码  收藏代码
  1. <Injectors target=”{BuddyListView}“>  
  2.            <PropertyInjector targetKey=”authUserName”       
  3.                                         source=”{LoginService}”   
  4.                                         sourceKey=”authUserName“/>  
  5.    
  6.  </Injectors>  
  7.    
  8. <Injectors target=”{Flex_Mate}“>  
  9.               <PropertyInjector targetKey=”viewStackSelectedIndex”   
  10.                                source=”{LoginService}”  
  11.                                sourceKey=”viewStackSelectedIndex“/>  
  12.    
  13.  </Injectors>  
  14.    
  15.    
<Injectors target=”{BuddyListView}“>            <PropertyInjector targetKey=”authUserName”                                              source=”{LoginService}”                                          sourceKey=”authUserName“/>    </Injectors>   <Injectors target=”{Flex_Mate}“>               <PropertyInjector targetKey=”viewStackSelectedIndex”                                 source=”{LoginService}”                                sourceKey=”viewStackSelectedIndex“/>    </Injectors>     

 

 

在此定义目标视窗、目标关键词,资源服务对象和资源关键词。 你根本不需要写任何glue code。

最后定义目标视窗: BuddyListView.mxml:

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" title="Buddy List of  {authUserName}" creationComplete="getBuddyList()" width="500" height="320">  
  3. <mx:Script>  
  4.     <![CDATA[ 
  5.         import mx.collections.ArrayCollection; 
  6.         import com.ny.flex.mate.event.GetBuddyListEvent; 
  7.        [Bindable] 
  8.        public var authUserName:String; 
  9.        [Bindable] 
  10.        public var buddyCollection:ArrayCollection; 
  11.         
  12.        private function getBuddyList():void{ 
  13.             var getBuddyListEvent:GetBuddyListEvent = new GetBuddyListEvent(GetBuddyListEvent.GET_BUDDY_LIST); 
  14.             getBuddyListEvent.authUserName = authUserName; 
  15.             dispatchEvent(getBuddyListEvent); 
  16.         } 
  17.     ]]>  
  18. </mx:Script>  
  19.   
  20.  <mx:DataGrid id="buddyList"  dataProvider="{buddyCollection}"  borderStyle="none" width="100%" height="100%" >  
  21.        <mx:columns>  
  22.         <mx:DataGridColumn dataField="firstName" headerText="First Name"/>  
  23.         <mx:DataGridColumn dataField="lastName" headerText="Last Name"/>  
  24.     </mx:columns>  
  25.   
  26.  </mx:DataGrid>  
  27. </mx:Panel>  
<?xml version="1.0" encoding="utf-8"?> <mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" title="Buddy List of  {authUserName}" creationComplete="getBuddyList()" width="500" height="320"> <mx:Script> 	<![CDATA[ 		import mx.collections.ArrayCollection; 		import com.ny.flex.mate.event.GetBuddyListEvent; 	   [Bindable] 	   public var authUserName:String; 	   [Bindable] 	   public var buddyCollection:ArrayCollection; 	    	   private function getBuddyList():void{ 			var getBuddyListEvent:GetBuddyListEvent = new GetBuddyListEvent(GetBuddyListEvent.GET_BUDDY_LIST); 			getBuddyListEvent.authUserName = authUserName; 			dispatchEvent(getBuddyListEvent); 		} 	]]> </mx:Script>   <mx:DataGrid id="buddyList"  dataProvider="{buddyCollection}"  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> 

 

 

 

 

 

整个开发流程是这样的:

 

 

Action–>Dispatch Event–>Config Handler–>create service–>Inject Bindable Object –>another Action….

 

整个项目结构图 见附件

 

 

总结:

在我5blog中讨论过的Flex编程框架中,哪一个是最好的呢?

我认为中央管理(central management)最适合进阶水准的小型项目。因为无须学习新的框架,并且也一样有清晰的架构。 而且 他也是走向框架的起点。

对于MateCairngorm,在我看来Mate略占上风,原因如下:

对于Cairngorm

1Cairngorm过于复杂,学习曲线较高

2,我觉得Cairngorm有一些垃圾代码(例如Frontcontroller,event 和Command)。

对于Mate

1,比Cairngorm更简单易学,貌似继承和发扬了Flex的特质。

2,从EventMap中得益,因为无须编写在事件和服务之间的黏着代码。

但另一个方面, EventMap也会带来痛苦,试想一下,用户有50个行为和100个对象需要绑定,那就需要在EventMap中写入大量的configration代码。那么EventMap就成为一个灾难。

因此,如果用户使用Cairngorm,就可以选用  Cairngorm without FrontContoller的方案。

对于Mate,如果使用Meta标签来代替EventMap,就无须设置太多的东西,示例如下:

[EventHadler ={name ="myHandler", serviceclass="myservice" result , taget ...}]

MateDispatch(myevent).

 

我在期待着它的来临。

 

posted @ 2011-05-02 15:44  Marksion  阅读(882)  评论(0编辑  收藏  举报