文档库 最新最全的文档下载
当前位置:文档库 › Spring Actionscript IOC 框架与 Flex Cairngorm MVC 应用开发的整合

Spring Actionscript IOC 框架与 Flex Cairngorm MVC 应用开发的整合

Spring Actionscript IOC 框架与 Flex Cairngorm MVC 应用开发的整合

--------------------------------------------------------------------------------

摘自: https://www.wendangku.net/doc/b214000793.html, 被阅读次数: 255


由 yangyi 于 2011-06-21 22:37:38 提供



-
要学习本教程,您需要有一定的 Flex 编程经验,以及对 Cairngorm MVC 和 Spring Actionscript IOC 框架有所了解。

Spring Actionscript 框架简介

Spring Actionscript 是一种类似于基于 Java 的 Spring IOC 框架的 Actionscript3 语言的实现,它可以应用于 Flash、Flex 和 AIR 的开发。这个框架不仅仅是一个能够支持控制反转的容器,它也提供了和现有的 Flex MVC 框架的集成方案,比如和 Cairngorm 的集成。本文就会着重介绍它如何与 Cairngorm MVC 集成在一起,发挥 IOC 与 MVC 的优势,使得 Flex 应用程序能够更大程度地实现灵活和健壮。在阅读本文之前,需要对 Spring Actionscript 和 Cairngorm 框架有所了解。


--------------------------------------------------------------------------------

回页首

Spring Actionscript 与 Cairngorm 集成的扩展点介绍

Spring Actionscript 框架提供了多个扩展点用于和 Cairngorm 框架集成,它会将 Cairngorm 的一些核心对象配置到 Spring Actionscript 的 IOC 容器内,其中的一些特性会使我们在使用这个 MVC 框架的时候更加容易,使得我们的代码更加灵活。这篇文章会从各个扩展点进行详细介绍,如何配置以及将二者结合起来使用。首先我们先了解一下有哪些扩展点需要集成:

ModelLocator 用于管理 Model 对象。
FrontController 用于管理事件和 Command 之间的绑定关系。
ServiceLocator 用于配置所有与后台通信的服务。
Command 工厂 用于创建 Command 对象
Delegate 工厂 用于创建 Delegate 对象
通过这些扩展点的集成,才会将 Sprint Actionscript 与 Cairngorm MVC 框架紧密的结合起来,才能更好的发挥二者的优势。下面我们分别仔细介绍一下各个扩展点是如何使用的:

ModelLocator

这是在 Cairngorm 框架中很重要的一个类,用于获取应用中的各个 Model 对象,例如想要获得一个 Model 的实例,你需要通过它的一个静态方法 ApplicationModel.getInstance() 方法。它大量的依赖于单例模式,在方便使用的同时,也使得你的代码和具体的 Model 实现类紧紧地绑定起来。而这正和“低耦合”的思想恰恰相反,想要解决这个问题,最好的解决办法是提供 Model 接口,用你的具体 Model 类去实现这个接口,通过面向接口的方式将 Model 注入到 Flex 应用中,首先我们创建一个简单的 Model 接口:


清单 1.

public interface IApplicationModel extends IEventDispatcher {

function get productItems():ArrayCollection;

[Bindable(event="productItemsChanged")]

function set productItems(value:ArrayCollection):void;

}




然后让你的具体的 ModelLocator 类现这个接口,就像下面的代码:


清单 2.

public class ApplicationModel extends EventDispatcher implements IModelLocator,
IApplicationModel{
private static var _modelInstance : IApplicationModel;

// 单例, 用以返回 model 实例
public static function getInstance():IApplicationModel {
if (!_modelInstance) {
_modelInstance = new ApplicationModel();
}

return _modelInstance;
}

public function ApplicationModel():void {
super();
if (_modelInstance) {
throw new Error('Only one ApplicationModel instance should be instantiated');
}
}

private var _productItems:ArrayCollection;

public function get productItems():ArrayCollection{
return _productItems;
}

[Bindable(event="productItemsChanged")]
public function set productItems(value:ArrayCollection):void{
if (value !== _productItems) {
_productItems = value;
dispatchEvent(new Event("productItemsChanged"));
}
}
}




现在我们将它配置到我们的 Spring ActionScript IOC 容器中,

factory-method="getInstance" scope="singleton"/>





现在我们用 IoC 容器来管理我们的 Model 类的创建,我们的代码里不需要 getInstance() 工厂方法了,当你使用了 scope="singleton" 属性,IoC 容器内会确保只有一个 Model 实例被创建。所有我们的 Model 类可以被重构为:


清单 3.

public class ApplicationModel extends EventDispatcher implements IModelLocator,
IApplicationModel {

public function ApplicationModel():void {
super();
}

private var _productItems:ArrayCollection;

public function get productItems():ArrayCollection {
return _productItems;
}

[Bindable(event="productItemsChanged")]
public function set productItems(value:ArrayCollection):void {
if (value !== _productItems) {
_productItems = value;
dispatchEvent(new Event("productItemsChanged"));
}
}
}




然后修改我们的配置文件,去掉工厂方法的配置:

scope="singleton"/>




就是这么简单,利用 Spring Ioc 容器使得我们的 Model 层的代码更加简洁。

FrontController

用过 Cairngorm 都知道 FrontController 类的重要,它是 MVC 框架中重要的中央控制器,它负责将我们的事件和我们的 Command 执行层绑定起来。在使用 Cairngorm 框架的时候,如果没有 IoC 容器管理,我们需要将 F

rontController 类和 ServiceLocator 类(稍后会提到)添加到你的主应用程序的 MXML 类中,从而编译到最终的 Swf 文件里。就像下面的代码:


清单 4.

xmlns:control="com.cairngormclasses.control.*"
xmlns:business="com.cairngormclasses.business.*"
xmlns:mx="https://www.wendangku.net/doc/b214000793.html,/2006/mxml"
layout="absolute">








在你的 FrontController 类中绑定事件和 commands 之后,FrontController 类会变得像下面一样:


清单 5.

public class Controller extends FrontController {

public static const SOME_ACTION:String = "SomeActionEventID";

public function Controller() {
super();
initializeCommands();
}
// 将事件和 command 绑定起来
public function initializeCommands():void {
addCommand( Controller.SOME_ACTION, SomeActionCommand );
}
}




这样的代码是可以运行的,但是将事件和 command 类的绑定关系写到 controller 类里面带来的问题是,如果需要改变这种绑定关系,就需要改写这个 Controller 类然后重新编译应用。于是 Spring Actionscript 框架提供了 CairngormFrontController,这个类允许将事件的 ID 和 Command 在 IoC 容器的配置文件中绑定起来。比如下面的配置:


清单 6.

scope="singleton">



// 绑定事件和 command




// 指明 commad 类所在的包路径







第一个参数是个对象,它包含事件 ID 和 Command 类的关联,第二个参数是指明 Command 类的包名。通过这样配置之后,我们就不再需要 FrontController 类了,但是我们还是必须将 Command 类编译到应用程序的 Swf 文件内用于运行期的动态反射

这样之后,我们之前的 FrontController 和 ServiceLocator 类就不需要在应用中声明了:


清单 7.

xmlns:control="com.cairngormclasses.control.*"
xmlns:business="com.cairngormclasses.business.*"
xmlns:mx="https://www.wendangku.net/doc/b214000793.html,/2006/mxml"
layout="absolute">
// 删除 FrontController 和 serviceLocator 的声明








ServiceLocator

现在我们来看看 ServiceLocator 类,在源代码里配置远程服务不是很方便,而且当

在开发时期和运行时期的远程服务路径不一致的时候就会带来一些麻烦,任何改变都需要重新编译应用程序。所以当引入 Spring Actionscript 之后,这些配置的改变就可以抽到 xml 配置文件里,任何改动都不要重新编译了。Spring Actionscript 提供的 CairngormServiceLocator 能够支持在 IoC 容器中配置服务,例如:


清单 8.

class="org.springextensions.actionscript.cairngorm.business.CairngormServiceLocator"
factory-method="getInstance">

// 用于指定需要用的 service

testService







元素 用于指定配置的 testService,它的配置定义如下:


清单 9.














Command 工厂

FrontController 通常用来实例化 Command 类,并将它绑定到事件上,在 Command 中,如果需要访问 Model 实例,通常的做法是直接调用 applicationModel.getInstance() 方法。这就是一种紧耦合的实现方式,而且这也会使得单元测试更加困难,所以如何在 Command 中注入别的实例,例如 Model,Spring Actionscript 提供了 IcommandFactory 接口去解决这个问题,这个接口非常简单,只需要实现以下两个方法:

public function canCreate(clazz:Class):Boolean;
public function createCommand(clazz:Class):ICommand




方法 canCreate 用于决定请求的 CommandClass 是否可以被具体的 Command 工厂创建,在这个方法里,你需要检查是否这个 Command 类实现了具体的接口,或者在运行期需找注入的 Command 类。CairngormFrontcontroller 实际上在内部实现了这个接口,ICommandFactory 实现了去检查是否某一个具体的类实现了了 ICommand 接口。

现在我们看看如何解决这个 model 注入的问题,我们先定义一个接口 IApplicationModelAware.

public interface IApplicationModelAware {
function set applicationModel(value:IApplicationModel):void;
}




然后可以去创建一个 Command 基类,它负责获取 model 的引用:


清单 10.

public class CommandBase extends AbstractResponderCommand
implements IApplicationModelAware {

public function CommandBase() {
super();
}

private var _appl

icationModel:IApplicationModel;

function get applicationModel():IApplicationModel {
return _applicationModel;
}
// 用于注入 model
function set applicationModel(value:IApplicationModel):void {
_applicationModel = value;
}
// 执行方法
override public function execute(event:CairngormEvent):void {
super.execute(event);
}
// 成功回调函数,需要被子类覆盖
override public function result(data:Object):void {
throw new Error("Not implemented in base class");
}
// 失败回调函数,需要被子类覆盖
override public function fault(info:Object):void {
throw new Error("Not implemented in base class");
}

}




下面我们去创建 Command 工厂类,它负责创建 Command 的子类,以及注入 model 的引用。


清单 11.

public class ApplicationModelAwareCommandFactory implements ICommandFactory,
IApplicationModelAware {
// 用于注入 model
private var _applicationModel:IApplicationModel;
function set applicationModel(value:IApplicationModel):void {
_applicationModel = value;
}

public function canCreate(clazz:Class):Boolean {
return (ClassUtils.isSubclassOf(clazz, CommandBase));
}
public function createCommand(clazz:Class):ICommand {
var result:CommandBase = new clazz();
result.applicationModel = _applicationModel;
return result;
}
}





我们看到 ApplicationModelAwareCommandFactory 实现了 IApplicationModelAware 接口,现在为了能够将 model 注入到我们的工厂类中,我们需要在 Spring Actionscript 容器中进行配置,首先配置 command 工厂:


清单 12.

class="com.myclasses.cairngorm.factories.ApplicationModelAwareCommandFactory"
scope="singleton">






接下来,我们需要将这个 command 工厂类也注入到我们的 controller 中:

class="org.springextensions.actionscript.cairngorm.control.CairngormFrontController"
scope="singleton">








// 配置 command 工厂

appAwareCmdFactory







现在,每一个添加到 FrontController 中的 command, 都会自动注入了 ApplicationModel 的引用,其他的注入类似。

Delegate 工厂

熟悉 Cairngorm 就会知道,delegate 类是用来和后台应用交互,发

送以及接受数据用的,往往在 command 中需要引用 delegate 来完成完整的业务逻辑。我们在 command 类中创建具体需要的 delegate 类的实例,就像下面的例子,直接创造具体的 delegate:


清单 13.

public class GetProductItemsCommand extends CommandBase {
private var _delegate:GetProductItemsDelegate;

public function GetProductItemsCommand() {
super();
//create the specific delegate class and pass ourselves as its responder
// 创建具体的 delegate 对象
_delegate = new GetProductItemsDelegate(this as IResponder);
}

override public function execute(event:CairngormEvent):void {
super.execute(event);
//execute the delegate logic
_delegate.getProductItems();
}

override public function result(data:Object):void {
// Business logic to handle the data retrieval
}

override public function fault(info:Object):void {
// Logic to handle errors
}

}




这样带来的问题就是我们将 command 和 delegate 又牢牢地绑定在了一起。如果需要改变使用的 delegate,就会带来一些不方便,而且需要重新编译。 基于这种问题,Spring Actionscript 提供了一个接口叫 IBusinessDelegate,我们的 delegate 例子继承这个接口:

public interface IGetProductItemsDelegate extends IBusinessDelegate {

function getProductItems():void;
}




这个接口的实现可以继承 Spring Actionscript 提供的 AbstractBusiesssDelegate 类


清单 14.

public class GetProductItemsDelegate extends AbstractBusinessDelegate
implements IGetProductItemsDelegate {

public function GetProductItemsDelegate(service:* = null,
responder:IResponder = null) {
super(service, responder);
}

public function getProductItems():void {
var token:AsyncToken = service.getProductItems();
token.addResponder(this.responder);
}
}




现在是时候去重构我们的 command 类了,我们的 command 类已经继承了 AbstractResponderCommand 类,这个基类已经包含了一个叫做 businessDelegate 的属性,我们不再需要手工去创建 delegate 的实例,我们只需要将需要的 delegate 注入进来,然后将 businessDelegate 属性转化成我们需要的 delegate 接口。


清单 15.

public class GetProductItemsCommand extends CommandBase {
public function GetProductItemsCommand() {
super();
}

override public function execute(event:CairngormEvent):void {
super.execute(event);
// 通过 businessDelegate 属性获得注入的 delegate 对象
IGetProductItemsDelegate(this.businessDelegate).getProductItems();
}

override public function result(data:Object):void {
// Business logic to

handle the data retrieval
}

override public function fault(info:Object):void {
// Logic to handle errors
}
}





接下里我们看如何将这个 delegate 注入到被 command 工厂创建出来的 command 中,Spring actionscript 提供了一个叫做 RespondCommandFactory 的类去完成这个工作,它提供了一个叫做 addBusinessDelegateFactory 的方法:需要将我们的 command 工厂继承它:


清单 16.

public class ApplicationModelAwareCommandFactory extends ResponderCommandFactory
implements IApplicationModelAware {

}




最后,我们需要配置到 IOC 配置文件中,我们首先来配置 BusinessDelegate 工厂:


清单 17.

class="org.springextensions.actionscript.cairngorm.business.BusinessDelegateFactory"
scope="singleton">

value="com.myclasses.delegates.GetProductItemsDelegate">






然后我们需要将这个 delegate 工厂和我们的 command 工厂联系起来:


清单 18.

class="com.myclasses.cairngorm.factories.ApplicationModelAwareCommandFactory"
scope="singleton">



businessDelegateFactory



https://www.wendangku.net/doc/b214000793.html,mands.GetProductItemsCommand









现在,我们基于 Cairngorm MVC 的应用都通过 Spring Actionscript 容器变得松散耦合起来了,今后很多的重构都只需要改改配置文件,Flex 应用的可维护性和可扩展性都得到了大大的提高。


--------------------------------------------------------------------------------

回页首

安装配置开发环境

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



相关文档 最新文档