1. Cairngorm简介
Cairngorm是一个Flex程序开发框架,基于MVC设计模式。
使用Cairngorm进行开发时我们一般涉及以下几个部件的开发:
ModelLocator:定义Model。ActionScript类,一般采用singleton模式实现,必须
是Bindable的
ServiceLocator:定义与之进行通讯的服务器端的服务。MXML Component
Event:继承CairngormEvent
Command:处理Event的逻辑。实现ICommand接口
Controller:注册Event与Command之间的对应关系。继承FrontController
Delegate:服务器端服务的代理。ActionScript类
以用户输入数据、点击确定按钮,客户端与服务器通讯,然后根据处理结果进行相应操
作这一典型的处理过程为例,确定按钮事件中,用户数据被附加到Event上然后发布,
Cairngorm根据Controller中注册的信息,找到处理该Event的Command,该Command通过
ServiceLocator获得相应的远程服务,从Event中提取用户数据发送到远程服务,响应回
来后,Command根据响应数据,通过ModelLocator修改数据,由于ModelLocator和页面数
据是Bind在一起的,所以也就相应地修改了画面的显示。
2. 示例
以下是用户输入ID、password进行登录的示例代码,当ID、password都是“test”的时候,
登录成功,画面转到有主菜单的画面。
服务器端简单地实现了一个服务,代码如下:
public class UserService {
public boolean isValid(String username, String password) {
if ("test".equals(username) && "test".equals(password)) {
return true;
} else {
return false;
}
}
}
客户端代码的包结构如下(其中方括弧表示包),其中没有使用Delegate:
login.mxml
[business]
Controller.as
Services.mxml
[commands]
LoginCommand.as
[events]
LoginEvent.as
[model]
ModelLocator.as
ModelLocator代码如下:
package model
{
[Bindable]
public class ModelLocator
{
static private var _instance : ModelLocator = null;
public var showLoginPanel : Boolean = true;
public var currentState : String = "";
static public function getInstance() : ModelLocator
{
if (_instance == null) {
_instance = new ModelLocator();
}
return _instance;
}
}
}
ServiceLocator代码如下:
<?xml version="1.0" encoding="utf-8"?>
<rds:ServiceLocator xmlns:rds="com.adobe.cairngorm.business.*"
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RemoteObject
id="userService"
destination="userServiceDestination"
endpoint="http://localhost:8080/test-server/messagebroker/amf">
</mx:RemoteObject>
</rds:ServiceLocator>
Event代码如下:
package business.events
{
import com.adobe.cairngorm.control.CairngormEvent;
public class LoginEvent extends CairngormEvent
{
static public var EVENT_ID:String="login";
public var username : String = null;
public var password : String = null;
public function LoginEvent()
{
super(EVENT_ID);
}
}
}
Command代码如下:
package business.commands
{
import com.adobe.cairngorm.business.ServiceLocator;
import com.adobe.cairngorm.commands.ICommand;
import com.adobe.cairngorm.control.CairngormEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;
import model.ModelLocator;
import business.events.LoginEvent;
public class LoginCommand implements ICommand
{
private var _modelLoc : ModelLocator = ModelLocator.getInstance();
private var _serviceLoc : ServiceLocator = ServiceLocator.getInstance();
public function execute(event:CairngormEvent):void
{
var loginEvent : LoginEvent = LoginEvent(event);
var userService : RemoteObject = _serviceLoc.getRemoteObject("userService");
userService.addEventListener(ResultEvent.RESULT, onResults_login);
userService.getOperation("isValid").send(loginEvent.username, loginEvent.password);
}
private function onResults_login(event:ResultEvent):void
{
var isValid : Boolean = Boolean(event.result);
if (isValid) {
_modelLoc.showLoginPanel = false;
_modelLoc.currentState = "mainmenu";
}
}
}
}
Controller代码如下:
package business
{
import com.adobe.cairngorm.control.FrontController;
import business.events.LoginEvent;
import business.commands.LoginCommand;
public class Controller extends FrontController
{
public function Controller()
{
super();
this.addCommand(LoginEvent.EVENT_ID, LoginCommand);
}
}
}
最后登录画面代码如下
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%" verticalAlign="middle" horizontalAlign="center"
fontFamily="Courier New" fontSize="12" currentState="{_model.currentState}">
<mx:states>
<mx:State name="mainmenu">
<mx:RemoveChild target="{panel1}"/>
<mx:AddChild position="lastChild">
<mx:MenuBar id="mainMenu" width="100%" x="0" y="0" labelField="@label">
<mx:XMLList>
<menuitem label="数据录入">
<menuitem label="顾客信息登记" />
<menuitem label="印刷订单录入" />
</menuitem>
<menuitem label="帮助">
<menuitem label="帮助" />
<menuitem label="关于" />
</menuitem>
</mx:XMLList>
</mx:MenuBar>
</mx:AddChild>
<mx:SetProperty name="layout" value="absolute"/>
</mx:State>
</mx:states>
<mx:Panel width="370" height="192" layout="absolute" title="登録" id="panel1" visible="{_model.showLoginPanel}">
<mx:Label text="姓 名:" x="44" y="21" width="91"/>
<mx:TextInput x="143" y="19" id="txtUsername" maxChars="32"/>
<mx:Label x="44" y="51" text="密 码:" width="91"/>
<mx:TextInput x="143" y="49" id="txtPassword" maxChars="32" displayAsPassword="true"/>
<mx:Button x="70" y="118" label="登录" id="btnLogin" click="btnLogin_clicked()" width="92"/>
<mx:Button x="170" y="118" label="重置" id="btnReset" click="btnReset_clicked()" width="92"/>
</mx:Panel>
<mx:Script>
<![CDATA[
import model.ModelLocator;
import business.events.LoginEvent;
[Bindable]
private var _model:ModelLocator=ModelLocator.getInstance();
private function btnLogin_clicked() : void
{
var event : LoginEvent = new LoginEvent();
event.username = txtUsername.text;
event.password = txtPassword.text;
event.dispatch();
}
private function btnReset_clicked() : void
{
//略
}
]]>
</mx:Script>
<rds:Services xmlns:rds="business.*"/>
<router:Controller xmlns:router="business.*"/>
</mx:Application>
其中需要注意的是Application的currentState和登录窗口的visible属性是bind到ModelLocator的。