Flex MVC框架-Flex_Cairngorm
有没有听说过这个奇怪的词汇:“Cairngorm”?如果你的回答是“No” &&你是Flex程序员,哪你就看看自己是不是住在一个井底。J
Cairngorm是Flex的一个MVC框架结构,名字取自苏格兰的一个山脉。(kao,如果是我建立一个自己的框架结构,我就取名叫:“xxx”。)
有关这个框架,在网络上有很多图表用来讨论。下面是我所理解的框架图表:
使用Cairngorm的第一步是建立框架结构的骨架,包括了三个对象:
Model Locater;
Service Locator;
Front Controller;
Model Locator:承载了组件之间的所有的传递的信息和数据,这是一个Bindable(可绑定的)对象。
Service Locator:定义了与数据源(Httpservice,Webservice,Remoteobject)之间通讯的界面。
Front Controller:建立播送事件(Dispatch event)和命令层(command)之间的对应关系(mapping)。
看一下相关的代码:
BuddyAppModelLocator.as:
Xml代码
1 <em>package com.ny.flex.cairngorm.model
2 {
3 import com.ny.flex.cairngorm.vo.User;
4
5 import mx.collections.ArrayCollection;
6
7 [Bindable]
8 public class BuddyAppModelLocator
9 {
10 public var buddyList:ArrayCollection=new ArrayCollection();
11 public var loginUser:User=new User();
12 public var viewStackSelectedIndex :int = 0;
13
14 static private var __instance:BuddyAppModelLocator=null;
15
16 static public function getInstance():BuddyAppModelLocator
17 {
18 if(__instance == null)
19 {
20 __instance=new BuddyAppModelLocator();
21 }
22 return __instance;
23 }
24 }
25 }
26 </em>
在Model Locator代码中,定义了三个public的变量,buddyList:用来存放由数据库获取的密友列表;loginUser:定义一个User类型对象;viewStackSelectedIndex:定义viewStack指向的视窗。
几乎所有的服务层返回的信息都需要在Model Locator中有一个相应的对象。
BuddyServiceLocator.mxml:
Xml代码
27 <em><em><?xml version=”1.0″ encoding=”utf-8″?>
28 <cairngorm:ServiceLocator xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns:cairngorm=”http://www.adobe.com/2006/cairngorm“>
29 <mx:RemoteObject id=”buddyRo“ destination=”flexmvcRO” >
30
31 </mx:RemoteObject>
32 </cairngorm:ServiceLocator>
33 </em></em>
上述代码定义了程序将要调用的RemoteObject ,RemoteObject 所调用的Destination需要和remote_config.xml文件中的Destination相一致。在此,Destination的值为“flexmvcRO”。
BuddyListController.as:
Xml代码
34 <em><em><strong>package com.ny.flex.cairngorm.control
35 {
36 import com.adobe.cairngorm.control.FrontController;
37 import com.ny.flex.cairngorm.command.GetBuddyListCommand;
38 import com.ny.flex.cairngorm.command.LoginCommand;
39 import com.ny.flex.cairngorm.event.GetBuddyListEvent;
40 import com.ny.flex.cairngorm.event.LoginEvent;
41
42 public class BuddyListController extends FrontController
43 {
44 public function BuddyListController()
45 {
46 super();
47 addCommand(LoginEvent.LOGIN_EVENT,LoginCommand);
48 addCommand(GetBuddyListEvent.GET_BUDDY_LIST_EVENT,
49 GetBuddyListCommand);
50 }
51
52 }
53 }
54 </strong></em></em>
很显然,上述的Controller代码是事件和命令的对应处理的地方。
如何能将这些乱七八糟的东西结合在一起?其Magic的地方是在主页(Main application)上,代码如下:
BuddList_Main_Cairngorm.mxml:
Xml代码
55 <em><em><strong><?xml version=”1.0″ encoding=”utf-8″?>
56 <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml“ xmlns:service=”com.ny.flex.cairngorm.service.*“ xmlns:controller=”com.ny.flex.cairngorm.control.*” xmlns:views=”com.ny.flex.cairngorm.views.*” layout=”absolute“ width=”100%” height=”100%“>
57 <mx:Script>
58 <![CDATA[
59 import com.ny.flex.cairngorm.model.BuddyAppModelLocator;
60 [Bindable]
61 public var myModel:BuddyAppModelLocator = BuddyAppModelLocator.getInstance();
62 ]]>
63 </mx:Script>
64
65 <service:BuddyServiceLocator id=”myservice“/>
66 <controller:BuddyListController id=”myController“/>
67
68 <mx:HBox horizontalAlign=”center” verticalAlign=”top“ width=”100%” height=”100%” y=”0” x=”0“>
69 <mx:ViewStack id=”viewStack“ resizeToContent=”true” selectedIndex=”{myModel.viewStackSelectedIndex}” >
70 <views:LoginView />
71 <views:BuddyListView/>
72 </mx:ViewStack>
73 </mx:HBox>
74 </mx:Application>
75 </strong></em></em>
现在用户可以建立视图组件,并从这些组件中播送事件:
LoginView.mxml:
Xml代码
76 <em><em><strong><em> <![CDATA[
77 import com.ny.flex.cairngorm.event.LoginEvent;
78 import com.ny.flex.cairngorm.vo.User;
79 import mx.validators.Validator;
80 private function login():void{
81 if(Validator.validateAll(validators).length == 0){
82 var loginUser:User = new User();
83 loginUser.userName=username.text;
84 loginUser.password=password.text;
85 var loginEvent:LoginEvent = new LoginEvent();
86 loginEvent.loginUser = loginUser;
87 loginEvent.dispatch();
88 }
89 }
90 ]]>
91 </mx:Script>
92
93 <!– Validators–>
94 <mx:Array id=”validators“>
95 <mx:StringValidator id=”userNameValidator” source=”{username}“ property=”text“ required=”true“/>
96 <mx:StringValidator id=”passwordValidator” source=”{password}“ property=”text” required=”true” />
97 </mx:Array>
98
99
100 <mx:Form id=”loginForm” x=”0” y=”0“>
101 <mx:FormItem label=”Username:” >
102 <mx:TextInput id=”username” />
103 </mx:FormItem>
104 <mx:FormItem label=”Password:” >
105 <mx:TextInput id=”password” displayAsPassword=”true” />
106 </mx:FormItem>
107 <mx:FormItem direction=”horizontal” verticalGap=”15” paddingTop=”5” width=”170“>
108 <mx:Button id=”loginBtn” label=”Login” click=”login()”/>
109 </mx:FormItem>
110 </mx:Form>
111
112 </mx:Panel>
113 </em></strong></em></em>
每一个动作都需要建立一个相应的事件:
LoginEvent.as:
Xml代码
114 <em><em><strong><em>package com.ny.flex.cairngorm.event
115 {
116 import com.adobe.cairngorm.control.CairngormEvent;
117 import com.ny.flex.cairngorm.vo.User;
118
119 import flash.events.Event;
120
121 public class LoginEvent extends CairngormEvent
122 {
123 public static var LOGIN_EVENT:String = “loginEvent”
124 public var loginUser:User ;
125
126 public function LoginEvent()
127 {
128 super(LOGIN_EVENT);
129 }
130
131 override public function clone() : Event
132 {
133 return new LoginEvent();
134 }
135 }
136 }
137 </em></strong></em></em>
每一个事件都要对应于一个命令:
LoginCommand.as:
Xml代码
138 <em><em><strong>package com.ny.flex.cairngorm.command
139 {
140 import com.adobe.cairngorm.commands.ICommand;
141 import com.adobe.cairngorm.control.CairngormEvent;
142 import com.ny.flex.cairngorm.event.LoginEvent;
143 import com.ny.flex.cairngorm.model.BuddyAppModelLocator;
144 import com.ny.flex.cairngorm.service.LoginDelegate;
145 import com.ny.flex.cairngorm.vo.User;
146
147 import mx.controls.Alert;
148 import mx.rpc.IResponder;
149
150 public class LoginCommand implements ICommand, IResponder
151 {
152 public function LoginCommand()
153 {
154 }
155
156 public function execute(event:CairngormEvent):void
157 {
158 var loginEvent:LoginEvent = LoginEvent(event);
159 var user:User = loginEvent.loginUser;
160 var lgoinService :LoginDelegate
161 = new LoginDelegate(this);
162 lgoinService.authenticate(user);
163 }
164
165 public function result(event:Object):void
166 {
167 var authUser:User = User(event.result);
168 BuddyAppModelLocator.getInstance().loginUser = authUser;
169 BuddyAppModelLocator.getInstance().viewStackSelectedIndex=1;
170 }
171
172 public function fault(info:Object):void
173 {
174 Alert.show(“Login Fail Error “);
175 }
176
177 }
178 }
179 </strong></em></em>
然后,在Front Controller(前端控制器)中build对应关系:
addCommand(LoginEvent.LOGIN_EVENT,LoginCommand);
命令层需要完成商务逻辑,用户需要在执行方法中加入商务逻辑代码:
Xml代码
180 <em><em><strong> var lgoinService :LoginDelegate =
181 new LoginDelegate(this);
182 lgoinService.authenticate(user);
183 </strong></em></em>
Delegate(代表)用来通过服务层(Service Locator)调用数据源:
LoginDelegate.as:
Xml代码
184 <em><em><strong><em>package com.ny.flex.cairngorm.service
185 {
186 import com.adobe.cairngorm.business.ServiceLocator;
187 import com.ny.flex.cairngorm.vo.User;
188
189 import mx.rpc.IResponder;
190
191 public class LoginDelegate
192 {
193 private var responder:IResponder;
194 private var service:Object;
195
196 public function LoginDelegate(responder :IResponder){
197 this.service =
198 ServiceLocator.getInstance()
199 .getRemoteObject(“buddyRo”);
200 this.responder = responder;
201 }
202
203 public function authenticate(user:User):void{
204 var call:Object = service.authenticate(user);
205 call.addResponder(responder);
206 }
207 }
208 }
209
210 </em></strong></em></em>
返回的结果将回复到命令层(LoginCommand.as)的结果方法中,在此方法中Model被更新,然后数据被绑定到结果视图上:
LoginCommand.as:
Xml代码
211 <em><em><strong> public function result(event:Object):void
212 {
213 var authUser:User = User(event.result);
214 BuddyAppModelLocator.getInstance().loginUser
215 = authUser;
216 BuddyAppModelLocator.getInstance().viewStackSelectedIndex=1;
217 }
218 </strong></em></em>
其它的视图工作流程同上,整个密友列表项目的结构如下图所示:
使用Cairngorm开发应用项目Layer,测试性高。并且使得程序员更专业化。
但这个框架的确很不容易学习和维护,那么有没有更好的方法简化它?
来看看:咔嚓Front Controller的Cairngorm。