基于 Cairngorm MVC 框架的 Flex 程序设计与开发

翟 峰, 开发工程师, IBM

翟峰在 J2EE 和 Web 开发领域有着多年开发经验,喜欢关注新技术。毕业于西北大学,拥有计算机硕士学位。

吴 镝, IBM 实习生, IBM

吴镝主要关注 J2EE 和 Web 开发领域,喜欢关注和学习新技术,目前就读于天津大学,攻读计算机科学与技术硕士学位。

简介: 随着富互联网应用程序(Rich Internet Application) 的发展,Flex 也得到了迅速的发展,然后随着 Flex 应用的项目的增大,传统的 Flex 开发已经显得层次不清,维护困难,在这样背景下,基于 Flex 的 MVC 框架Cairngorm 应运而生。本文将介绍系统的讲解 Cairngorm,通过本教程的学习,您可以全面掌握使用 Cairngorm 框架进行 Web 开发。

标记本文!

发布日期: 2010 年8 月 16 日
级别: 中级
访问情况 : 4364 次浏览
评论: 3 (查看 | 添加评论 - 登录)

平均分 (17个评分)
为本文评分

 

Cairngorm 框架简介

Cairngorm 是一种 MVC 框架,它可以帮助开发者很好的组织代码,分层,从而使得代码更加清晰易懂,可以使设计者,UI 组件开发者,数据服务开发者并行工作,从而提高开发效率。Cairngorm 由五大组件构成,分别作为存放数据的仓库 (ModelLocator),存放服务的仓库 (ServiceLocator),处理业务逻辑的命令 (Command),自定义的用于触发命令执行的事件 (Event),用于把事件映射到命令的前端控制器 (FrontController)。它应用了代理模式,命令模式,观察者和单例等几种设计模式。


回页首

Cairngorm 详解

ModelLocator: 用于保存应用程序的数据,与HttpSession 类似,区别主要在于数据是保存客户端,实现时将 ModelLocator 实现为单例,所有的应用数据都存储在唯一的一个 ModelLocator 对象中。

CairngormEvent: 这个类由 Cairngorm 框架提供,位于包 com.adobe.cairngorm.control,所有的自定义的事件类都必须继承CairngormEvent,在自定义事件类中定义 VO 的引用,可以通过它来存储从 View 层传递过来的 VO。

ICommand: 命令接口,位于包 com.adobe.cairngorm.commands,每个命令类需要实现 ICommand 接口,命令类用于处理业务逻辑,通过实现其 execute 方法来实现业务逻辑。execute 方法以事件作为参数,通过传入的事件中包含的详细信息来进行相应的处理。

FrontController: 前端控制器,位于包com.adobe.cairngorm.control,自定义的前端控制器必须继承FrontController,它主要用于完成 CairngormEvent 和 ICommand 之间的映射。

CairngormEventDispatcher:CairngormEvent 的分发器,位于包 com.adobe.cairngorm.control

Delegate: 服务代理,一般定义一个 Delegate 类,持有 ServiceLocator 的引用,Delegate 类是唯一的了解 Service 有关的类。


回页首

系统处理流程


图 1. 使用Cairngorm 后系统处理流程

在基于 Cairngorm 的应用程序中,应用程序的数据都放在一个仓库中,这个仓库就是ModelLocator,整个应用程序只生成维护一个 ModelLocator 的实例,在需要数据的组件中引用这个实例。比如视图需要数据进行渲染,那么视图就维护 ModelLocator 实例的引用,在视图中触发事件后,事件通过前端控制器映射为一个对应的命令,然后命令通过调用服务代理,执行相应的逻辑,命令通过更新自身维护的 ModelLocator 的引用,因为 ModelLocator 只有一个,这样就相当于更新了视图。


回页首

安装配置开发环境

开始前先让我们来搭建我们的开发环境:

下载并安装JDK(本文使用版本为 Sun JDK 6)

下载并解压Eclipse(本文使用版本为 Eclipse Ganymede J2EE SR2 版本 )

下载并安装FB3_WWEJ_Plugin.exe(Flex Builder 4 plug-in for eclipse)

下载并安装 Tomcat 6.x

安装 FB3_WWEJ_Plugin.exe 过程中选中 eclipse 安装目录。


回页首

一个入门的例子

前面我们讲解了 Cairngorm 的基本概念和一些主要的角色和类,下面我用一个简单的员工管理系统的例子来进一步的理解开发过程。

解压出来就是一个 Cairngorm.swc 文件

  • 新建 Flex Project


图 2. 新建项目

Next 配置服务器


图 3. 配置服务器

点击 Finish.

将Cairngorm.swc 拷贝到项目的 flex_libs 目录下。

在flex_src 目录下建好包结构


图 4. 建立包结构

每个包中存放的内容一目了然

  • 定义视图
  1. 在 views 包中新建一个 MXML Component, 基于 Panel,取名为 PeopleInfo.mxml,如图所示 :

    图 5. 新建 Panel
  2. 在里面添加一个 DataGrid, 还有一些文本框和按钮 , 如图 6 所示:

    图 6. 视图

三、这里我们希望当 Panel 加载完成后,从服务器读取 xml 文件,将员工信息给读入 DataGrid 中,这里,为了简单明了,仅仅定义了员工 id 和 name 属性。所以在 Panel 中添加属性 creationComplete="LoadPersons();",然后添加<mx:Script>标签,并添加LoadPersons()方法,原型如下所示:


清单 1. 原型

                              

public

functionLoadPersons():void

 {

 }

 

  • 定义 ModelLocator

视图中的 DataGrid 是需要数据进行渲染的,下面定义数据的仓库 ModelLocator,该类维护一个 ArrayCollection personInfos 的引用,它就是应用程序所需的数据。

新建一个 Actionscript class,取名为 ModelLocator.as,代码如下:


清单 2.ModelLocator.as

                              

 package model

 {

                import mx.collections.ArrayCollection;

                [Bindable]

                public class ModelLocator

                {

                        private static var __instance:ModelLocator=null;

 //以下这个 ArrayCollection用于填充 DataGrid

       public var personInfos:ArrayCollection = new ArrayCollection();

                        public static  function getInstance():ModelLocator

                        {

                                if(__instance == null)

                                {

                                       __instance=new ModelLocator();

                                }

 return __instance;

                        }

                }

 }

 

ArrayCollection 对象 personInfos 用于存储从 xml 读出的员工信息。

  • 定义事件

在event 包中新建一个 ActionScript class,取名为 LoadPersonsEvent.as,该事件必须继承于 CairngormEvent,通过 CairngormEventDispatcher 来分发 , EVENT_ID用来唯一的标识一个事件,代码如下:


清单 3.LoadPersonsEvent.as

                              

 package event

 {

                import com.adobe.cairngorm.control.CairngormEvent;

 

 public class LoadPersonsEvent extends CairngormEvent

                {

 //事件名称

                        public static var EVENT_ID:String = "LoadPersons";

                        public function LoadPersonsEvent()

                        {

                                super(EVENT_ID);

                        }

                }

 }

 

  • 在页面中注册并分发事件

在PeopleInfo.mxml 的 <mx:Panel> 下面添加如下代码:


清单 4.

                              

 <mx:Metadata>

                [Event(name="LoadPersons",type="event.LoadPersonsEvent")]

 </mx:Metadata>

 

type 属性就是类的完整路径。

在LoadPersons() 方法中添加如下代码:


清单 5.

                              

 var e:LoadPersonsEvent = new LoadPersonsEvent();

 e.dispatch();

 

当事件分发后,通过 FrontController 将事件映射为命令,然后命令更新ModelLocator 中的数据的时候,从而引起 DataGrid 的变化,从中可以看出,需要在页面中维护一个 ModelLocator 单例的引用 , 代码如下:

然后在 <mx:Script> 中添加以下代码:


清单 6.

                              

 [Bindable]

 public var _model:ModelLocator = ModelLocator.getInstance();

 

然后将 _model.personInfos 作为 DataGrid 的 dataProvider, 为 <mx:DataGrid> 添加如下属性:


清单 7.

                              

dataProvider="{_model.personInfos}"

                      

 

  • 定义 FrontController

事件分发后,应该执行一个对应的命令,命令通过执行相应的业务逻辑,更新数据,从而视图得到更新,那到底事件和命令之间是如何映射的呢?

在包 control 中新建一个 ActionScript class,取名为 MyFrontControl.as,代码如下:


清单 8.MyFrontControl.as

                              

 package control

 {

                import com.adobe.cairngorm.control.FrontController;

 import event.*;

                import commands.*;

                public class MyFrontControl extends FrontController

                {

                        public function MyFrontControl()

                        {

                                super();

                      

 //注册一个事件,将其与一个命令绑定

                      

 this.addCommand(LoadPersonsEvent.EVENT_ID,LoadPersonCommand);

                        }

              

                }

 }

 

这里的 addCommand() 方法将事件和命令关联起来 , 第一个参数是事件的 name,第二个参数是具体的命令类,这里 LoadPersonCommand 还没有定义,编译错,下面就来定义 LoadPersonCommand.

  • 定义 Command

新建一个 ActionScript class,取名为 LoadPersonCommand.as,实现 ICommand 接口,

命令调用服务代理完成相应的逻辑,然后通过更新数据,间接的反映到视图上,所以命令中需要维护 ModelLocator 单例的引用,每个命令类的入口函数是 execute() 方法。

代码如下:


清单 9.LoadPersonCommand.as

                              

 package commands

 {

                import com.adobe.cairngorm.commands.ICommand;

                import com.adobe.cairngorm.control.CairngormEvent;

                import mx.collections.ArrayCollection;

                import mx.controls.Alert;

                import mx.rpc.Responder;

 import mx.rpc.events.FaultEvent;

                import mx.rpc.events.ResultEvent;

                public class LoadPersonCommand implements ICommand

                {

                        public function execute(event:CairngormEvent):void

                        {

 

                        }

              

 //如果请求发送成功则执行这个方法

 public function onResults_loadPersons(event:ResultEvent):void

                        {

                              

                        }

 //如果请求失败则执行这个方法

                        public function onFaults_loadPersons(event:FaultEvent):void

                        {

                              

                        }

              

                }

 }

 

execute() 方法具体怎么实现,需要依赖于 service, 下面就来定义 ServiceLocator

  • 定义 ServiceLocator

在business 包下新建一个 MXML Component,取名为 ServiceLocator.mxml,由于插件不支持com.adobe.cairngorm.business.ServiceLocator,所以 Based on暂时随便选择,等会手工修改,修改后的代码如下:


清单 10.ServiceLocator.mxml

                              

 <?xml version="1.0" encoding="utf-8"?>

 <rds:ServiceLocator xmlns:rds="com.adobe.cairngorm.business.*"

 xmlns:mx="http://www.adobe.com/2006/mxml">

     <! —服务 -->

     <mx:HTTPService  id="getPersonInfos" url="/xml/abc.xml"/>

 </rds:ServiceLocator>

 

这里定义了一个 HTTPService 服务,获取服务器下的 xml 目录下的 abc.xml 的内容,在 WebContent 目录下建立一个目录,取名为 xml,并且在其下建立一个 abc.xml,内容如下:


清单 11. abc.xml

                              

 <menus>

 <Box>

   <id>1</id>

 <name>zhangsan</name>

 </Box>

 <Box>

        <id>2</id>

        <name>lisi</name>

 </Box>

 <Box>

        <id>3</id>

        <name>wangwu</name>

 </Box>

 </menus>

 

前面提到,通过定义 delegate 类来对服务进行管理易于维护,以下定义 delegate 类

  • 定义 Delegate 类

在business 包下新建一个 delegates 包,在其下建立一个 ActionScript class 类,取名为 PersonDelegate.as,该方法通过引用 ServiceLocator,获取并调用其中的服务,代码如下:


清单 12.PersonDelegate.as

                              

 package business.delegates

 {

                import com.adobe.cairngorm.business.ServiceLocator;

                import mx.rpc.http.HTTPService;

                import mx.rpc.IResponder;

                import mx.rpc.AsyncToken;

                import mx.controls.Alert;

                public class PersonDelegate

                {

         public var serviceLocator:ServiceLocator = ServiceLocator.getInstance();

                      

                        public var _service:HTTPService;

                      

                        public var _responder:IResponder;

                      

                        public function PersonDelegate(responder:IResponder)

                        {

 //getHTTPService的参数对应 Services.mxml中的 id

        _service = serviceLocator.getHTTPService("getPersonInfos");

                                _responder = responder;

                        }

                      

                        public function getPersonInfos():void

                        {

 //发送请求

                                var token:AsyncToken = _service.send();

                                token.addResponder(_responder);

                        }

 

                }

 }

 

方法 getPersonInfos() 用于发送查询 abc.xml 文件的请求。

  • 定义 VO

从xml 文件中读取过来的数据实际上都是一个个的员工的信息,便于存储,定义 VO 类来封装员工信息,在 vo 包中定义 ActionScript class,取名为 PersonForm.as,代码如下:


清单 13.PersonForm.as

                              

 package vo

 {

                 public class PersonForm

                {

                        public var id:String="";

                        public var name:String="";

                        public function PersonForm()

                        {

                      

                      

                        }

                }

 }

 

  • 实现 Command

通过在 Command 中维护 ModelLocator 单例的引用,当更新 ModelLocator 中的数据时,因为 ModelLocator 是单例,所以页面中的 ModelLocator 中的数据也相应的更新,详细的原理请看注释,LoadPersonCommand.as完整代码如下:


清单 14.LoadPersonCommand.as

                              

 package commands

 {

import business.delegates.PersonDelegate;

import com.adobe.cairngorm.commands.ICommand;

import com.adobe.cairngorm.control.CairngormEvent;

import model.ModelLocator;

import mx.collections.ArrayCollection;

import mx.controls.Alert;

import mx.rpc.Responder;

import mx.rpc.events.FaultEvent;

import mx.rpc.events.ResultEvent;

import vo.PersonForm;

public class LoadPersonCommand implements ICommand

 {

        private var _model:ModelLocator=ModelLocator.getInstance();

        public function execute(event:CairngormEvent):void

        {

        //注册两个回调函数

var responder:Responder =

new Responder(onResults_loadPersons, onFaults_loadPersons);

var delegate:PersonDelegate = new PersonDelegate(responder);

        delegate.getPersonInfos();

        }

        //如果请求发送成功则执行

 public function onResults_loadPersons(event:ResultEvent):void

        {

        //用 xml 文件中的数据填充 ArrayCollection

        var personRaw:ArrayCollection =event.result.menus.Box;

        //personInfo填充 Model

        for(var i:int=0;i<personRaw.length;i++)

        {

        var tempPerson:PersonForm=new PersonForm();

        var personFromXML:Object=personRaw.getItemAt(i);

        tempPerson.id=personFromXML.id;

        tempPerson.name=personFromXML.name;

        _model.personInfos.addItem(tempPerson);

        }

        }

        //如果请求发送不成功则执行

 public function onFaults_loadPersons(event:FaultEvent):void

        {

        Alert.show("failed");

        }

        }

 }

 

execute() 方法中 PersonDelegate 执行 getPersonInfos() 方法,当请求发送成功,返回数据的时候,通过注册的回调函数 onResults_loadPersons(event:ResultEvent) 接收返回的数据,将每条员工信息用 VO 封装起来,然后更新 ModelLocator 中的数据,从而页面上的数据得到更新。

  • 创建 MXML Application

以上将所有的组件已经创建完毕,现在是时候创建一个 Application 将它们组装起来。

在flex_src 下新建一个 MXML Application,取名为 Cairngormdemo.mxml,代码如下:


清单 15.Cairngormdemo.mxml

                              

 <?xml version="1.0" encoding="utf-8"?>

 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"

                xmlns:views="views.*"

                xmlns:rds="business.*"

                xmlns:control="control.*">

         <mx:Style source="assets/style.css"/>

       

                <views:PeopleInfo  x="51"/>

                <rds:Services />

                <control:MyFrontControl/>

       

       

 </mx:Application>

 

在页面中将自定义组件 PeopleInfo,ServiceLocator 和 FrontController 实例化。

  • 运行

运行 Cairngormdemo.mxml,如下图所示 :


图 7. 结果

这里仅仅实现了加载数据的功能,增删改留给读者自己实现。


回页首

结束语

本文对 Flex MVC 框架 Cairngorm 的重要部分作了一个详细的介绍,当然还有一些细节问题值得研究,相信通过本文的示例项目,可以帮助您更快的掌握这种全新的开发方式。

 


回页首

下载

描述

名字

大小

下载方法

演示代码

Cairngormdemo.zip

699KB

HTTP

关于下载方法的信息

 

参考资料

学习

developerWorksWeb 2.0 资源中心,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 Web 2.0 新手入门 栏目,迅速了解 Web 2.0 的相关概念。
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值