2. Flex IOC 框架概览
控制反转(Inversion of Control,IOC),也称为依赖注入(Dependency Injection,DI),在过去几
年中已经成为流行的软件设计模式,从而导致许多 Flex 开发者投入到此类框架的探索,其中就包括
Spring ActionScript, Parsley, Flicc 和 Swiz。
概括地说,IOC 是一种软件设计模式,其中使用独立的对象负责为其它对象的字段填充正确的实现,
而不是这些对象自己负责。这样的好处是,你可以通过接口声明对象的字段,从而将对象及其实现进
行分离(所谓按契约设计)。另外,通过在对象中拆除创建逻辑,使得对象的目的更为明确。
IOC 容器都会提供一组类库, 帮助你以一致和声明的方式使用这个模式。 把这种模式和接口进行结合,
可以帮助你创建可测试的和非常灵活的对象。对于 IOC 模式更深度的描述,请参见 Martin Fowler 的
文章 Inversion of Control Containers and the Dependency Injection pattern。
Java 和.Net 的 IOC 框架早已存在,最近在 Flex 社区内,有关这个领域的话题相当活跃。
在这篇文章中,我将介绍其中的一些 IOC 框架,简要概述它们是如何工作的,以及对它们进行比较。
基于比较不同框架实现的需要,我将使用 Spring ActionScript, Parsley, Flicc 和 Swiz 框架分别开发
同一个基准项目:ProfileViewer。
要求
为了完成本文的大部分内容,你需要以下软件和文件:
Flex 4 beta
试用
了解更多信息
Flash Builder 4 beta
下载
了解更多信息
范例文件:
profileviewer_samples.zip (ZIP, 1 MB)
必备知识
Flex 知识是需要的。
2
3. Flex IOC 框架概览
IOC 概念
配置对象有两个最常见的方式:
实例化对象(例如,myObject = new Object())
获取对象(例如,var myObject = registry.getMyObject())
使用 IOC,你在一个独立层实例化应用程序对象,然后传递依赖到需要它们的对象。这种情况也有两
个常用的方式:
setter 注入(例如,instance.myObject = new Object())
构造函数注入(例如,instance = new Instance( new Object()) )
一个 IOC 框架通常包括三个主要部分:配置,工厂和注入机制。
配置
配置用来描述对象之间的相互关系。 描述配置最常用的一个方式是在一个文件中声明它。此文件有时
称为上下文(contex)文件。配置也可以使用元数据/注解或编程方式。
工厂
工厂解析配置并准备所有对象,一旦应用程序运行,这些对象就可以被检索。在传统的 Spring(最
流行的 Java IOC 框架)中,所有对象(我称它们为客户对象 )被 IOC 容器预先准备,在需要它们
的对象中使用接口声明对它们的依赖。在上下文配置文件中为声明的依赖设置使用特定的实现类。
注入机制
注入机制是一种手段,借助它将工厂创建的实例注入到应用程序或另一个实例。
在 Spring 中,web 应用程序通过 web.xml 文件完成此事。Spring 监听被加载的 web 应用程序
(webapp) 上下文。 此刻 Spring 启动类加载器,类加载器负责加载任何需要创建的对象。 工厂会(如
需要)实例化对象,并填充该对象的所有依赖,这些依赖在将实例返回给应用程序之前可能需要被实
例化(这也称为“将它们编织在一起”)。
类加载的工作方式在 Flex 中有所不同,因此,编织需要做的事情也不同。
对此,当前有两种选择:
客户端对象可以从工厂请求一个对象(编织好了的)
注入可以使用内置的 Flex 事件机制在初始化视图时来触发
你探索一些框架之后,对这些概念会更为清晰。
3
4. Flex IOC 框架概览
ProfileViewer 介绍
我将使用 ProfileViewer 项目来比较各个框架,它是一个非常简单的应用程序,由两个界面组成:登
录面板和信息面板 (dashboard) ProfileViewer 使用简单的模型视图控制器
。 (Model-View-Controller,
MVC)架构和表现层模型(Presentation Model)模式。
注意:此基准测试应用程序只是一个例子,它可能有其它的编码方式。它基于我所了解的一些流行模
式。如果你觉得我使用框架的方式并非它的原始目的,请让我知道。我很乐意根据反馈信息和改进建
议对程序作出调整。
所有范例的源代码都在 Google Code flex-ioc-examples project 上。
当你阅读文章的其余部分时,我强烈建议你下载并打开源代码。
高级架构
在开发图形用户界面应用程序时,通常会采用 MVC 模式。在此我不会讨论这个模式的细节,如果你
需要更多信息,请参阅 Model-view-controller 。
在此之上,我实现了一个服务层(见图 1)。这是程序集成的地方,在这里应用程序从后端系统获取
数据。在范例中,我首先创建应用程序的这部分功能。
最后,我使用了表现层模型模式,程序中每一个视图都对应有一个模型,模型中包含视图的状态和逻
辑。视图响应模式的变化,一般通过绑定表达式。这可以让你单元测试视图的逻辑。欲了解这一主题
的更多信息 ,请参见 Martin Fowler’s explanation of the Presentation Model 或 Paul Williams’
post 。
图 1.初始架构
4
5. Flex IOC 框架概览
标识改进
更改 ProfileViewer 使用 IOC 框架之后,我将对象实例及其依赖的管理移交给 IOC 层(见图 2)。有
些 IOC 框架支持编织(wiring up)事件到动作,它使你能够建立一个控制器层。在适当的情况下,
我会利用 IOC 框架所提供的这个能力。
图 2.修改后的 IOC 架构
5
6. Flex IOC 框架概览
下面,我简要概述使用 IOC 框架之后应用程序可以改进的部分。
对象获取
当用户成功登录后,应用程序会获取两个对象回来(译者注:一个是 User 对象,一个是 Friends 对
象)。这两个对象的详细资料在不同的视图显示给用户。在信息面板的表现层模型 DashboardPM 的
准备过程中,我执行查找两个对象实例:
在 MainPM 中:
public function set authenticated( value : Boolean ) : void
{
//..
var locator : ModelLocator = ModelLocator.getInstance();
dashboardPM = new DashboardPM( locator.user, locator.friends );
//..
}
在这个例子中,ModelLocator 是一个单例模式,用于存储模型对象。
使用单例模式 ,我可以在应用程序的任何地方访问相同的对象实例,因为只有一个实例可以被声明
创建。在这种情况下,我可以安全访问 User 和 Friends,在其它任何地方使用的都是相同的实例。
虽然这是有益的,但使用单例也有缺点,其中之一,它会使得单元测试变得困难,因为在整个测试套
件期间,你都必须关注对象的生命周期。这是因为在测试用例中,单例使用静态引用存储,不具有被
垃圾收集的资格。
对象传递
尽量减少应用程序使用单例而导致影响的方法是层次性传递对象。
你可以在 DashboardPM 的构造函数中看到这种方式。它需要一个 User 模型和一个 Friends 模型。
表现层模型将这些实例传递给其子女,尽管它只是使用 User 对象。这是一个坏的实践做法,其中一
个对象依赖于它不直接使用的其它对象。
对于一个小的范例应用程序,这可能不会产生麻烦,但当你的应用程序规模增加时,可以想像,这种
方法可能需要做大量的工作。它还在你的类中增加了不应该存在的噪声。如果你可以只使用它需要的
项实例化对象,代码会更加清洁。
最后,初始 ProfileViewer 有一个表现层模型的层次结构,这样我可以传递对象,使用 IOC 框架之后
我将不再需要这个层次结构,我会将它删除。
配置服务层
对于范例应用程序来说,非视图层的配置有待增强。在这个例子中表现为类 LoginDelegate,其中创
建了自己的 RemoteObject 实例。
6
7. Flex IOC 框架概览
Spring ActionScript
框架: Spring ActionScript
站点: http://www.herrodius.com/blog/
开发者: Christophe Herreman
版本: 0.71
版权: Open source
配置: XML
Spring ActionScript (之前称为 Prana)是一个相当知名的框架,以成熟度而闻名, Christophe
由
Herreman 开发。
核心概念
Spring ActionScript 对于使用过 Spring(.NET 版本或 Java 版本)的人来说应该很熟悉。在运行时加
载配置文件,这个文件给予工厂足够的信息,可以实例化任何应用程序请求的对象。
Spring ActionScript 基本配置
在基准项目上使用 Spring ActionScript 需要三个基本步骤:
1. 创建一个 application-context.xml 文件
2. 在程序中初始化工厂对象
3. 在视图层(或其它任何地方)需要的地方,从工厂获取对象以供使用
对象工厂和对象配置
使用 Spring ActionScript,对象声明被添加在一个应用程序可以访问到的 XML 文件中(通常命名为
application-context.xml)。这个配置文件之后会被 XMLApplicationContext 类加载,该类是
ObjectFactory 的子类。
在我的实现中,我将这些初始化操作置于两个对象中:ContextLoader 和 Inject。
ContextLoader 获取应用程序上下文文件的路径。该文件在 XMLApplicationContext 中加载。在应用
程序的根部:
private function init() : void{
ContextLoader.contextPath = "application-context.xml";
}
幕后 ContextLoader 正在加载 Spring ActionScript 上下文:
public static function set contextPath( value : String ) : void{
_contextPath = value;
applicationContext = new XMLApplicationContext( _contextPath );
applicationContext.addEventListener( Event.COMPLETE,
handleLoadComplete );
}
applicationContext.load();
7
10. Flex IOC 框架概览
Spring ActionScript 摘要
Spring ActionScript 是一个伟大的、成熟的 IOC 框架,并有活跃的发展路线图。它所使用的术语对于
使用过 Spring 的人应该非常熟悉。
使用 XML 来声明对象是有一点麻烦的, 有时你会在 XML 中声明类, 但这个类未被包含在 SWF 中(因
为在应用程序没有该类的直接引用) ,这将导致 Flash Player 在运行时抛出异常。这个问题的解决方
案是创建 ActionScript 类,在上下文 XML 中声明依赖,并在应用程序中包含它。
10