Cairngorm是Flex的一个MVC框架结构
使用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代码
1. <EM><EM><?xml version=”1.0″ encoding=”utf-8″?>
2. <cairngorm:ServiceLocator xmlns:mx=”http://www.adobe.com/2006/mxml” xmlns:cairngorm=”http://www.adobe.com/2006/cairngorm“>
3. <mx:RemoteObject id=”buddyRo“ destination=”flexmvcRO” >
4.
5. </mx:RemoteObject>
6. </cairngorm:ServiceLocator>
7. </EM></EM>
上述代码定义了程序将要调用的RemoteObject ,RemoteObject 所调用的Destination需要和remote_config.xml文件中的Destination相一致。在此,Destination的值为“flexmvcRO”。
BuddyListController.as:
Xml代码
1. <EM><EM><STRONG>package com.ny.flex.cairngorm.control
2. {
3. import com.adobe.cairngorm.control.FrontController;
4. import com.ny.flex.cairngorm.command.GetBuddyListCommand;
5. import com.ny.flex.cairngorm.command.LoginCommand;
6. import com.ny.flex.cairngorm.event.GetBuddyListEvent;
7. import com.ny.flex.cairngorm.event.LoginEvent;
8.
9. public class BuddyListController extends FrontController
10. {
11. public function BuddyListController()
12. {
13. super();
14. addCommand(LoginEvent.LOGIN_EVENT,LoginCommand);
15. addCommand(GetBuddyListEvent.GET_BUDDY_LIST_EVENT,
16. GetBuddyListCommand);
17. }
18.
19. }
20. }
21. </STRONG></EM></EM>
很显然,上述的Controller代码是事件和命令的对应处理的地方。
如何能将这些乱七八糟的东西结合在一起?其Magic的地方是在主页(Main application)上,代码如下:
BuddList_Main_Cairngorm.mxml:
Xml代码
1. <EM><EM><STRONG><?xml version=”1.0″ encoding=”utf-8″?>
2. <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%“>
3. <mx:Script>
4. <![CDATA[
5. import com.ny.flex.cairngorm.model.BuddyAppModelLocator;
6. [Bindable]
7. public var myModel:BuddyAppModelLocator = BuddyAppModelLocator.getInstance();
8. ]]>
9. </mx:Script>
10.
11. <service:BuddyServiceLocator id=”myservice“/>
12. <controller:BuddyListController id=”myController“/>
13.
14. <mx:HBox horizontalAlign=”center” verticalAlign=”top“ width=”100%” height=”100%” y=”0” x=”0“>
15. <mx:ViewStack id=”viewStack“ resizeToContent=”true” selectedIndex=”{myModel.viewStackSelectedIndex}” >
16. <views:LoginView />
17. <views:BuddyListView/>
18. </mx:ViewStack>
19. </mx:HBox>
20. </mx:Application>
21. </STRONG></EM></EM>
现在用户可以建立视图组件,并从这些组件中播送事件:
LoginView.mxml:
Xml代码
1. <EM><EM><STRONG><EM> <![CDATA[
2. import com.ny.flex.cairngorm.event.LoginEvent;
3. import com.ny.flex.cairngorm.vo.User;
4. import mx.validators.Validator;
5. private function login():void{
6. if(Validator.validateAll(validators).length == 0){
7. var loginUser:User = new User();
8. loginUser.userName=username.text;
9. loginUser.password=password.text;
10. var loginEvent:LoginEvent = new LoginEvent();
11. loginEvent.loginUser = loginUser;
12. loginEvent.dispatch();
13. }
14. }
15. ]]>
16. </mx:Script>
17.
18. <!– Validators–>
19. <mx:Array id=”validators“>
20. <mx:StringValidator id=”userNameValidator” source=”{username}“ property=”text“ required=”true“/>
21. <mx:StringValidator id=”passwordValidator” source=”{password}“ property=”text” required=”true” />
22. </mx:Array>
23.
24.
25. <mx:Form id=”loginForm” x=”0” y=”0“>
26. <mx:FormItem label=”Username:” >
27. <mx:TextInput id=”username” />
28. </mx:FormItem>
29. <mx:FormItem label=”Password:” >
30. <mx:TextInput id=”password” displayAsPassword=”true” />
31. </mx:FormItem>
32. <mx:FormItem direction=”horizontal” verticalGap=”15” paddingTop=”5” width=”170“>
33. <mx:Button id=”loginBtn” label=”Login” click=”login()”/>
34. </mx:FormItem>
35. </mx:Form>
36.
37. </mx:Panel>
38. </EM></STRONG></EM></EM>
每一个动作都需要建立一个相应的事件:
LoginEvent.as:
Xml代码
1. <EM><EM><STRONG><EM>package com.ny.flex.cairngorm.event
2. {
3. import com.adobe.cairngorm.control.CairngormEvent;
4. import com.ny.flex.cairngorm.vo.User;
5.
6. import flash.events.Event;
7.
8. public class LoginEvent extends CairngormEvent
9. {
10. public static var LOGIN_EVENT:String = “loginEvent”
11. public var loginUser:User ;
12.
13. public function LoginEvent()
14. {
15. super(LOGIN_EVENT);
16. }
17.
18. override public function clone() : Event
19. {
20. return new LoginEvent();
21. }
22. }
23. }
24. </EM></STRONG></EM></EM>
每一个事件都 要对应于一个命令:
LoginCommand.as:
Xml代码
1. <EM><EM><STRONG>package com.ny.flex.cairngorm.command
2. {
3. import com.adobe.cairngorm.commands.ICommand;
4. import com.adobe.cairngorm.control.CairngormEvent;
5. import com.ny.flex.cairngorm.event.LoginEvent;
6. import com.ny.flex.cairngorm.model.BuddyAppModelLocator;
7. import com.ny.flex.cairngorm.service.LoginDelegate;
8. import com.ny.flex.cairngorm.vo.User;
9.
10. import mx.controls.Alert;
11. import mx.rpc.IResponder;
12.
13. public class LoginCommand implements ICommand, IResponder
14. {
15. public function LoginCommand()
16. {
17. }
18.
19. public function execute(event:CairngormEvent):void
20. {
21. var loginEvent:LoginEvent = LoginEvent(event);
22. var user:User = loginEvent.loginUser;
23. var lgoinService :LoginDelegate
24. = new LoginDelegate(this);
25. lgoinService.authenticate(user);
26. }
27.
28. public function result(event:Object):void
29. {
30. var authUser:User = User(event.result);
31. BuddyAppModelLocator.getInstance().loginUser = authUser;
32. BuddyAppModelLocator.getInstance().viewStackSelectedIndex=1;
33. }
34.
35. public function fault(info:Object):void
36. {
37. Alert.show(“Login Fail Error “);
38. }
39.
40. }
41. }
42. </STRONG></EM></EM>
然后,在Front Controller(前端控制器)中build对应关系:
addCommand(LoginEvent.LOGIN_EVENT,LoginCommand);
命令层需要完成商务逻辑,用户需要在执行方法中加入商务逻辑代码:
Xml代码
1. <EM><EM><STRONG> var lgoinService :LoginDelegate =
2. new LoginDelegate(this);
3. lgoinService.authenticate(user);
4. </STRONG></EM></EM>
Delegate(代表)用来通过服务层(Service Locator)调用数据源:
LoginDelegate.as:
Xml代码
1. <EM><EM><STRONG><EM>package com.ny.flex.cairngorm.service
2. {
3. import com.adobe.cairngorm.business.ServiceLocator;
4. import com.ny.flex.cairngorm.vo.User;
5.
6. import mx.rpc.IResponder;
7.
8. public class LoginDelegate
9. {
10. private var responder:IResponder;
11. private var service:Object;
12.
13. public function LoginDelegate(responder :IResponder){
14. this.service =
15. ServiceLocator.getInstance()
16. .getRemoteObject(“buddyRo”);
17. this.responder = responder;
18. }
19.
20. public function authenticate(user:User):void{
21. var call:Object = service.authenticate(user);
22. call.addResponder(responder);
23. }
24. }
25. }
26.
27. </EM></STRONG></EM></EM>
返回的结果将回复到命令层(LoginCommand.as)的结果方法中,在此方法中Model被更新,然后数据被绑定到结果视图上:
LoginCommand.as:
Xml代码
1. <EM><EM><STRONG> public function result(event:Object):void
2. {
3. var authUser:User = User(event.result);
4. BuddyAppModelLocator.getInstance().loginUser
5. = authUser;
6. BuddyAppModelLocator.getInstance().viewStackSelectedIndex=1;
7. }
8. </STRONG></EM></EM>
其它的视图工作流程同上,整个密友列表项目的结构如下图所示: