IOC(Inversion of Control),也称DI(Dependency Injection),是近年来在软件开发中变得非常流行的一种设计策略。众多的Flex开发者,探索出了诸如Spring ActionScript、Parsley、Flicc和Swiz这样的IOC框架。

什么是IOC?一言以蔽之,IOC是一种软件设计模式。借助IOC,可用一个独立的对象为其他对象的数据成员填充正确的实现,而不是由这些对象自己负责此项工作。这样做的好处有两个。第一,可将对象的数据成员声明为接口,从而将对象与其具体实现分离(即契约式设计,design by contract)。第二,可从对象中删除创建逻辑,可以使对象的用途更为明确。

IOC容器提供一个框架,你可借此以一致和宣告的形式使用这个模式。将此模式和接口结合起来,可以创建出易于测试、使用灵活的对象。有关IOC模式更深入的讨论,请参看Martin Fowler的文章Inversion of Control Containers and the Dependency Injection pattern。

Java和.NET的IOC框架早已建立,在Flex社区,近来也有不小的进展。

本文将讨论Flex中的一些IOC框架的工作原理、使用方法,并对这些框架进行比较。为了比较方便,我将在同一个工程(ProfileViewer)中使用Spring ActionScript、 Parsley、Flicc和Swiz这几个框架。

IOC的概念

一般有两种最常见的对象配置方法:

  • 对象实例化(例如:myObject = new Object() )
  • 对象查找(例如: var myObject = registry.getMyObject() )

而利用IOC,你可在一个独立层中实例化应用程序要用到的对象,并传入它们所需的依赖。具体来说,最常见的实现方法也有两种:

  • Setter注入(例如: instance.myObject = new Object() )
  • Constructor注入(例如: instance = new Instance( new Object() ) )

一个IOC框架,通常由如下三个部分组成:配置、工厂和注入机制。

配置

我们可以在配置中描述对象之间的关系。最常用的配置描述方法是在文件中声明。这样的文件有时候也被称为上下文文件(context file)。也可以用元数据/注释(metadata/annotation),甚至直接在程序中描述配置。

工厂

工厂负责配置的解析和所有对象的准备工作,程序一旦运行,就可以根据需要取得这些对象。

在经典的Spring框架(最流行的Java IOC框架)中,所有对象(我称其为客户对象)都由IOC容器负责准备,并且它们以接口形式声明自己的依赖。在配置文件中,被声明的依赖都被设置为对应的实现类。

注入机制

所谓注入机制,是指如何将工厂创建的对象实例注入到应用或其他对象。

就Spring Web应用而言,注入方法是通过web.xml来实现的。Spring会监听webapp上下文的加载事件,并利用钩子捕获类加载器的行为,从而分离出任何需被创建的对象。此后,若有需要,工厂将实例化对象,并填充它所需的依赖。当然在向应用返回对象之前,这些依赖本身也可能需要实例化。这个过程即所谓的 “(将依赖与对象)捆绑在一起”。

在Flex中,类的加载原理有所不同,因此捆绑方法也就不同。

目前有两种方法:

  • 客户对象直接从工厂请求(已捆绑好的)对象
  • 利用内置的Flex事件机制(用于实例化视图)触发注入

到后面我们具体讨论框架时,这些概念会更容易理解。

ProfileViewer介绍

ProfileViewer是一个非常简单的应用,只有两个界面(一个登录面板、一个仪表盘),接下来我们就用这个工程比较、讨论四个框架。 ProfileViewer使用了MVC(Model-View-Controller)架构和Presentation Model模式。

说明: 我将ProfileViewer建立自己过去看到的一些较为流行的设计模式基础上,仅仅是一个例子,使用这些框架肯定还有其他使用方法。如果你觉得我的方法有任何问题,请一定告诉我。我非常乐意根据大家的意见和建议调整改进。

本文所有例子的源代码可从flex-ioc-examples project下载。

我建议打开这些源码,对照着阅读本文下面的内容时。

高层架构

开发GUI应用时,通常会用到MVC模式。我们就不在这里深入讨论MVC本身的细节了,如果有需要请参看可参看Model-view-controller。

在此之上,我实现了服务层 (见图1)。应用可在这里得到来自后端系统的数据。在本例中,我简化了这个部分的实现。

最后,我使用了Presentation Model模式,应用中每个视图都有对应的模型,模型包含了它的状态和逻辑。正常情况下,视图通过绑定表达式响应模型的状态变化。这样,对视图逻辑做单元测试是没有问题的。有关更多细节,请参看Martin Fowler对Presentation Model模式的说明或Paul Williams的文章。

图1. 初期架构

架构改进

为把IOC框架引入ProfileViewer,我需将对象实例及其依赖的管理转移到IOC层(见图2)。一些框架支持将事件关联到Action,藉此可以搭建一个Controller层。我将在适当的地方使用框架提供的这些功能。

图2. 引入IOC后的框架

接下来,我主要说明通过引入IOC,应用中可得到改善的部分。

对象查找

用户登录成功后,应用取回两个对象。这两个对象包含的信息会在不同的视图中展示给用户。当准备仪表盘的表现层模型(DashboardPM)时,我需查找这两个对象实例:

在MainPM中:

public function set authenticated( value : Boolean ) : void { //.. var locator : ModelLocator = ModelLocator.getInstance(); dashboardPM = new DashboardPM( locator.user, locator.friends ); //.. }

ModelLocator使用了单例模式,用于存储模型对象。

依靠单例,我在应用的任何地方得到都是相同的对象实例,因为仅仅创建一个对象实例。在这种情况下,我可以安全访问UserFriends,因为在任何地方,它们都只有一个实例。

不过,单例也有其不足,比如造成单元测试困难——在测试套件整个存在期内,你都必须关注对象的生命周期。因为单例独立于测试用例,静态存储而不会被当做垃圾收集。

对象传递

弱化应用中单例负面影响的办法之一,是按类的继承层次传递对象。

你可以在DashboardPM的构造器的实现中看到这一点。它需取得User和Friends模型,然后由表现层模型将这些实例传递给自己的子类(尽管实际上只会用到User对象)。一个对象依赖于另一个实际并不直接使用的对象,这显然是一种糟糕的设计实践。

对于小的例子程序而言,这不会是什么大问题,但随着应用规模的扩张,你可以想象这种方法会带来多大的工作量。它也会给你的类带入本不需要的杂质。如果你能只实例化需要的对象,代码将变得更为干净。

最初的ProfileViewer的表现层模型被配置成继承结构,利用它可以实现对象的传递;引入IOC后,这个继承结构就不需要了,我会将其删除。

配置服务层

实现非视图层的配置,是对本例的一个有力支持。在本例中通过LoginDelegate类来表述,这个类会创建它自有的RemoteObject实例。

Spring ActionScript

  • 框架: Spring ActionScript
  • 网站: http://www.herrodius.com/blog/
  • 开发者: Christophe Herreman
  • 版本:0.71
  • 许可:开源
  • 配置: XML
  • Spring ActionScript前身为Prana,因其成熟度高,成为了一个知名框架。

核心概念

任何使用过Spring的Java或.NET版本的人,都会很快熟悉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(); }

接着在需要依赖的视图中,我创建一个Inject标签(受一个同事在Parsley中实现的启发)。利用这个标签,我可以很方便的声明我需将何种依赖添加到该视图。例如,在应用启动时,我有如下代码:

<springActionscript:Inject property="pm" objectId="{ ContextIds.MAIN_CONTAINER_PM }"/> <springActionscript:Inject property="controller" objectId="{ ContextIds.CONTROLLER }"/>

这将向XMLApplicationContext请求一个IDCONTROLLER的对象,并将它赋给视图中的成员变量controller

这是在视图层获取对象的好办法。

说明: Christophe Herreman曾撰文 说明如何用metadata实现上述类型的注入(类似Swiz 框架 ,但这种方法有性能问题,因为要读取元数据,视图需序列化为XML。

设置控制器

Spring ActionScript已计划发布一个支持MVCS的的扩展版。但在目前版本中,我将实现一个自有的控制器,并利用Spring ActionScript将处理程序挂接到事件源。

在最初的程序中,控制器会监听所有事件。当它截获到一个事件后,会查找所有处理器,筛选出能处理这个事件的对象。在经过修改后的例子中,不再监控整个显示列表,转而在application-context.xml中将事件源和事件处理器配对。

为此,我增加了一个新类ControllerPair,它负责事件源和处理器的配对。所有对被传递给SimpleController,并在它的init 函数中初始化每个对。

<object id="controller" class="com.adobe.login.control.SimpleController"> <method-invocation name="init"></method-invocation> <property name="controllerItems"> <array><ref>controllerItem</ref></array> </property> </object> <object id="controllerItem” class="com.adobe.login.control.ControllerPair"> <property name="dispatcher" ref="loginPM"/> <property name="handler" ref="handler"/> </object>

请注意其中的method-invocation标签,我们用它来指定对象被创建后马上自动调用的函数。在这里,被自动调用的函数是init(),它负责将事件派发者绑定到事件处理器。N

表现层模型的注入

在非IOC版的ProfileViewer中,为了实现对象的传递,表现层模型被配置为继承式结构。在IOC版中,我将删除此结构,以便每个表现层模型都能被配置为对应的视图。

尽管这样做,应用更易于配置和测试,但也有其缺点。在某些情况下,要实现离散的表现层模型之间的交互,需要做不少工作。

Spring ActionScript同时支持setter和constructor两种形式的注入。我更倾向于使用construtor注入,因为它可以完全暴露对象运作所需的全部依赖。如下是DashboardPM的配置:

<object id="dashboardPM" class="com.adobe.dashboard.presentationModel.DashboardPM"> <constructor-arg ref="user"/> </object>

在XML中声明构造函数的参数时,顺序应和对象的构造函数所期望的参数顺序相同。上面代码中的ref表示引用在上下文中声明的另一个对象,在这里即User

配置服务层

LoginHandler引用了代理对象,代理对象又依赖于另一个远程对象,该远程对象可以调用后端系统的功能。

下面,我们用setter完成这些对象的配置。需通过setter传入的实例包括代理对象和AuthenticationClient(这是一个用于检查用户是否已登录的接口)。MainPM具体实现了AuthenticationClient。

在这里,我将代理设计为存根,依赖于一个远程对象。配置如下:

<object id="handler" class="com.adobe.login.control.handler.LoginHandler"> <property name="client" ref="mainPM"/> <property name="user" ref="user"/> <property name="friends" ref="friends"/> <property name="delegate" ref="loginDelegate"/> </object> <object id="loginDelegate" class="com.adobe.login.service.LoginDelegate"> <property name="remoteObject" ref="remoteObject"/> </object> <object id="remoteObject" class="mx.rpc.remoting.RemoteObject"> <property name="destination" value="SPRING_ACTIONSCRIPT_DESTINATION"/> </object>

总结

Spring ActionScript是一个优秀的、成熟的、开发活动十分活跃的IOC框架。它使用的术语,应该说是任何用过Spring框架的人都熟悉的。

以XML形式声明对象存在一个问题,即在XML中声明一个类,并且这个类没被包含在SWF中(因为在你的应用中没有对它的直接引用)时,Flash Player会在运行时抛出异常。其解决办法是创建一个ActionScript类,声明它对上下文XML的依赖,并将此类包含在应用中。

Parsley

  • 框架: Parsley
  • 网站:http://www.spicefactory.org/
  • 开发者: Jens Halm
  • 版本: 2.0.0
  • 许可:开源
  • 配置: XML/MXML/ActionScript
  • Parsley也是一个成熟的IOC框架,最初灵感来源于Spring。它近期经历过一次较大规模的重写。新版本支持一些本地Flex特性,如绑定和元数据,使你在配置你的工程时有更多更好的选择。

核心概念

Parsley的核心概念是源自于Spring的上下文,也即应用的依赖注入的配置。

Parsley的配置现在支持多种形式,其中包括XML和MXML。你可以使用本地的MXML标记或Parsley库提供的自定义MXML标签。Parsley使用元数据标签实现对注入机制的支持,这和Swiz框架是类似的。

Parsley还支持消息模式。基本不需代码干预,你就能将你的对象配置为事件源或事件处理器。在这个例子中,我会用这个特性替代Controller模式。

基本配置

Parsley的配置分三个基本步骤:

  1. 创建Config.mxml文件。
  2. 在应用的根部初始化一个Context对象。
  3. 在你的视图中,用Inject元数据实现依赖的注入。

准备配置文件的方法有多种,不过在这个例子中,我使用支持本地标记和Parsley标签的MXML文件。这种方法的好处是在编译时就将类引入,当然这样一来,也就不能直接修改已被编译的应用的配置了。

对象工厂和对象配置

在Config.mxml中,你能看到应用中用到的从域模型到代理的所有对象。声明这些对象的方式有两种:

  1. 标准的MXML
  2. 使用Parsley的对象定义标签

在后面的内容中,我将详细介绍这种方法。

设置控制器和LoginHandler

我在这里不再使用自己编写的控制器,转而使用Parsley的消息系统(其设计决定了它对你编写的对象的影响很小)。具体是用元数据来实现。Parsley将事件源绑定到事件处理器,需要一个在Context可见且具有元数据的对象。

在这个例子应用中,LoginPM是事件源,LoginAction(从LoginHandler重命名而来)是事件处理器。

如下代码摘自LoginPM:

[Event( name="LOGIN", type="com.adobe.login.control.event.LoginEvent")] [ManagedEvents("LOGIN")] public class LoginPM extends EventDispatcher { ... public function login() : void { var event : LoginEvent = new LoginEvent( username, password ); dispatchEvent( event ); } }

让LoginPM成为事件源需要三个要素:Event元数据标签、ManagedEvents元数据标签,以及EventDispatcher#dispatchEvent。三者当中,只有ManagedEvents是Parsley扩展而来。Event元数据仅为习惯做法,事件的实际派发工作是由dispatchEvent完成的。Parsley将通过ManagedEvents决定它要处理哪个事件,并将该事件委托给事件处理器。

如下代码摘自LoginAction(已经被配置为事件处理器):

public class LoginAction implements IResponder { [MessageHandler] public function execute( event : LoginEvent ) : void { ... } }

因为我为这个函数补充了MessageHandler元数据,Parsley将把这个对象/函数当做类型为LoginEvent的所有事件的监听器。

要让这些对象对Parsley可见,可在传入FlexContextBuilder的配置文件内声明这些对象,或在视图中使用Configure对象。

表现层模型的注入

和其他例子一样,我已将表现层模型的继承结构去除。相关原因请参看Spring ActionScript。

Parsley支持setter和constructor两种注入方法。像我在Spring ActionScript例子中提到的那样,我更倾向于使用constructor注入,因为它可以暴露出对象运作所需的全部依赖。如是是DashboardPM的配置:

<spicefactory:Object type="{ DashboardPM }"/>

如果你的对象构造函数需要参数,则应该用Object标签予以声明,因为这样的参数在本地MXML中是不支持的。

要完成此构造函数,你需向类中添加一些元数据:

[InjectConstructor] public class DashboardPM { public var user : User; public function DashboardPM( user : User ) { this.user = user; } ... }

这里的元数据标签InjectConstructor,表示要求Parsley给DashboardPM的构造函数注入一个类型为User的、已声明过的对象。

若使用setter注入,你仅需在类中增加元数据标签Inject。例如,我在Config中用标准MXML声明SummaryPM

<dashboard:SummaryPM/>

接着,在类文件中有如下代码:

public class SummaryPM { [Inject] public var friends : Friends; ... }

这里的Inject标签表示需将一个类型为Friends的实例注入到SummaryPM。

总结

经过其他一些框架的不断启发,新版本的Parsley已发展成为一个完整的IOC框架。它还支持模块式开发和上下文卸载。在模块化Flex应用开发日益盛行的今天,这无疑是一个十分重要的特性。

Flicc

  • 框架: Flicc
  • 网站: http://flicc.sourceforge.net/
  • 开发者: Mike Herron
  • 版本: 0.5
  • 许可:开源
  • 配置: MXML

在IOC领域,Flicc是一个不太知名的后来者。它的配置方法(利用MXML文件)略有不同。它在MXML中有自己的对象定义标记,借此可将预先存在的对象传入工厂,并添加依赖(如传入一个视图)。

在MXML中声明依赖的好处,是依赖在编译时就被包含到应用中,这样可避免在应用运行时由于依赖的丢失造成异常。当然其缺点也是明显的,即不重新编译程序,依赖就不能改变。

对象工厂和对象配置

在Filcc中,将Configure标签添加到视图后,可以传入要配置的实例。另外也可以传入已经存在的实例并进行配置——和我在Spring ActionScript实现中使用过的Inject标签类似。

基本配置

  1. 创建一个从MXMLObjectFactory继承的配置类。
  2. 创建一个Filcc实例并传入配置。
  3. 在需要的地方,将Configure标签添加到你的视图中。
<FliccListener> <MxmlObjectFactory> <Config/> </MxmlObjectFactory> </FliccListener>

MxmlObjectFactory标签被添加到应用的根部。MxmlObjectFactory上一层的FliccListener标签,表示要求Flicc拣选出由Configure标签派发的应用程序显示列表中的事件。Config.mxml是我的配置文件。

设置控制器

和Parsley类似,Filcc支持在配置文件中将事件和对象绑定,尽管它并不使用控制器这个概念。

我利用这种方法将控制器绑定到事件源(即LoginPM)。当LoginPM派发它的事件时,事件被控制器截获,随后调用对应的处理器。

<Object objectId="controller" clazz="{ SimpleController }"> <handlers> <EventHandler eventName="{ LoginEvent.LOGIN }" handler="handleEvent"> <source> <Ref to="loginPM"/> </source> </EventHandler> </handlers> <handlerArray> <List clazz="{ Array }"> <Ref to="loginHandler"/> </List> </handlerArray> </Object>

我们在控制器中查找给定类型的事件,并触发execute方法:

public function handleEvent( event : Event ) : void { getHandlerForEventType( event.type ).execute( event ); }

表现层模型的注入

同样,在这个例子中,我删除了表现层模型间的继承结构。

Flicc 也支持setter或constructor这两种注入方法。

Filcc有两类基本的对象标签:ComponentObjectComponent用于描述你想配置的、已经存在的对象。Object则用于创建新实例。例如:

<Object objectId="dashboardPM" clazz="{ DashboardPM }"> <constructor> <Ref to="user"/> </constructor> </Object>

和Spring ActionScript、Parsley类似,你应按对象期望的顺序声明对象构造函数的参数。Ref表示引用声明在同一个上下文中的其他对象,该对象的标识用to属性表示。

Component和Object类似,但仅能依靠setter注入,因为Component描述的是已经存在并被传入Flicc的对象:

<Component objectId="main"> <controller> <Ref to="controller"/> </controller> <pm> <Ref to="mainPM"/> </pm> </Component>

如上的Component表示主应用,具有两个依赖:一个控制器、一个pm变量。

配置服务层

LoginHandler依赖于LoginDelegate,后者又依赖于RemoteObject。

配置如下:

<Object objectId="loginDelegate" clazz="{ LoginDelegate }"> <remoteObject> <Ref to="remoteObject"/> </remoteObject> </Object> <Object objectId="remoteObject" clazz="{ RemoteObject }"> <destination> FLICC_DESTINATION </destination> </Object>

上述代码声明了一个新的LoginDelegate实例,并填充了它对RemoteObject的依赖。

总结

Flicc不同于前面讨论过的两个框架,它的声明方式为MXML。当然这只是一个形式,所有框架的基本原理都是相同的。

在MXML中定义配置,可节省开发时间,因为类被编译进应用,运行时就不必花时间处理外部文件的载入和解析。因其API和先前两个框架有所不同,要熟练运用可能得花点时间。

Swiz

  • 框架: Swiz
  • 网站: http://swizframework.org
  • 开发者: Chris Scott, Sönke Rohde, Ben Clinkinbeard & Darron Schall
  • 版本: 0.6.2
  • 许可:开源
  • 配置: MXML + Metadata

Swiz也是一个新兴的IOC框架,但不仅限于此。它旨在发展成为一个完整的RIA(Rich Internet Application)架构下的解决方案。Swiz利用MXML定义对象,但有着不同的注入机制。

核心概念

Swiz提供了一个用来简化SwizConfig应用初始化的类。这个类有一个加载进Swiz实例的配置文件。此配置文件使用标准的MXML声明格式和一个定制的Prototype标签,用来创建带有构造器声明的对象。Swiz会根据注入的定义,从类中读取元数据,并由此判定要在何地注入何种对象。这个方法在Java领域很常见,先是在Spring 2.5中有Annotations支持,后来在Google Guice中也有类似的功能。

有了元数据,你的对象包含的信息更为丰富,你的配置文件也更清晰。

基本配置

  1. 创建Bean文件
  2. 为应用增加SwizConfig,并交给Bean文件
  3. 将元数据添加到你想注入依赖的类中

在Swiz中,你可在应用程序的根部加载Bean集合:

<swizframework:SwizConfig strict="true" mediateBubbledEvents="true" beanLoaders="{[ AppBeans ]}" viewPackages="com.adobe.login.view,com.adobe.dashboard.view" logEventLevel="{ LogEventLevel.WARN }"/>

获得具体的Bean,在Swiz中就有两种方法了:

Swiz.getBean( "loginHandler" )

或使用元数据:

[Autowire] public var pm : DashboardPM

有关其他可能的方法,请参看Swiz文档。但若使用元数据注入,需记住的是,类必须包含在显示列表中,否则注入无效。上述代码来自于 DashboardPanel。

在底层,Swiz会监听被添加到显示列表的全部对象,并通过反射判断这些对象是否包含注入元数据。为读取元数据,这些对象必须被序列化为XML,因此存在性能问题。要避免这一点,你可以在SwizConfig中使用viewPackage属性指定一个包,从而可以在包这个层次上限制哪个类可以被监听到。

设置控制器

Swiz在指定通过Swiz内部机制派发的事件的处理函数方面做得很好。

我在LoginHandler中增加如下元数据:

[Mediate(event="LOGIN", properties="username,password")] public function login( username : String, password : String ) : void

然后在事件源(LoginPM)如按如下派发事件:

dispatchEvent( new LoginEvent( username, password ) );

要使其正常工作,你需要能激活SwizConfig中的事件。这就意味着Swiz将监听在视图层级中出现的事件。如果你无法激活这些事件的话,那么就用下面这个语句:

Swiz.dispatchEvent( new LoginEvent( username, password ) );

但是这样一来,你就将代码绑定到框架上了。

AbstractController

ProfileViewer应用不会做任何真正的异步请求,Swiz可以为你提供一些有用的类,以管理这些调用。AbstractController提供了一个"executeServiceCall"方法,会创建动态的Responder对象,避免了自己写样本代码的麻烦。另外,Swiz还提供了一个 TestUtil类,让你创建模拟的服务调用和结果。

表现层模型的注入

和前面几个框架一样,我在这里仍将表现层模型配置为无继承结构。定义如下:

<local:MainPM id="mainPM"/> <login:LoginPM id="loginPM"/> <factory:Prototype id="dashboardPM" xmlns:factory="org.swizframework.factory.*" classReference="{ DashboardPM }" constructorArguments="{[ user ]}" />

声明是标准的MXML声明。Prototype标签让你可以描述对象,而不是创建一个实例。这样的话,就可以将构造器声明传递给对象。在类中的描述为:

public class MyClass { [Autowire] public var myDependency : MyModel; … }

Swiz会尝试自动通过类型匹配,也就是说你必须一个Bean对应一个相对应的类型。如果那个类没有,或者多余一个Bean,你就必须指定一个Bean 名。注意,在LoginController中有一个AuthenticationClient的依赖,也是MainPM实现的一个接口。

配置服务层

在这个例子中,我将LoginHandler命名为LoginController,这是因为它将扩展Swiz的AbstractController

public class LoginController extends AbstractController { [Autowire] public var client : AuthenticationClient; [Autowire] public var user : User; [Autowire] public var friends : Friends; [Autowire] public var delegate : LoginDelegate; [Mediate(event="LOGIN", properties="username,password")] public function login( username : String, password : String ) : void { executeServiceCall( delegate.authenticate( username, password ), result ); } }

AbstractController为你提供一个函数:executeServiceCall,它会为异步调用增加结果和错误监听器。你需要指定一个结果句柄,和一个错误句柄(可选)。这也可以帮你避免自己撰写样本代码的麻烦。

这一点和其他的例子有微小的不同,这是第一次在action里展示AbstractController,但是也展示了另外一个Swiz函数:TestUtil.mockResult。这个helper函数将模拟一个异步请求,这在没有后端要回调的情况下做开发是很有用的。

public class LoginDelegate { //only included for illustrative purposes //to show that swiz has configured it correctly. [Autowire] public var remoteObject : RemoteObject; public function authenticate( username : String, password : String ) : AsyncToken { var mockResult : * = { user : MockModelFactory.createUser( username ), friends : MockModelFactory.createFriends() } return TestUtil.mockResult( mockResult ); } }

总结

Swiz中定义注入的方法与众不同,它有许多可以简化开发过程的特性。这些特性可以移除对样本代码的需要,从而帮你将精力放在应用的业务端。

下一步工作

本文简要介绍了一些比较知名的Flex框架下的IOC容器,未被提及的有Mate和SmartyPants。Mate支持IOC,但不仅限于此。我最初打算在本文中准备一个Mate的例子,但后来觉得还是先深入学习后再写。写完这个例子后,我会在Google code上公布。SmartyPants和Swiz类似,也是利用元数据表述注入,值得一看。

本文是在Flex应用中使用IOC的入门读物,另外也是对各种框架做一比较,希望对你有所帮助。文章不能兼顾到这些框架的方方面面,建议你阅读它们的文档,了解更多细节。

转载于:https://www.cnblogs.com/moondev/archive/2013/01/30/2883044.html

常用Flex IOC框架比较分析【转载】相关推荐

  1. 【IOC框架】分析与理解

    1 IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图1:软件系统中耦合的对象 如果我们打开机械 ...

  2. RPC调用框架比较分析--转载

    原文地址:http://itindex.net/detail/52530-rpc-%E6%A1%86%E6%9E%B6-%E5%88%86%E6%9E%90 什么是RPC:  RPC(Remote P ...

  3. 简单介绍一下Java常用的五大框架!

    Java框架在Java开发中的作用是毋庸置疑的.那么Java常用框架有哪些?大概包括:Hibernate.Spring.Struts.jQuery.Redis五种.这些框架有什么用呢?Java常用框架 ...

  4. .NET的轻量级IOC框架芮双随笔

    面向对象的设计的重用性一直是他的一个重要特性,为了有效定义这一特性,又引申出面向对象设计的几个原则:高内聚.低耦合.功能单一.优先使用聚合.面向接口编程等.依赖这些原则和前人的经验,又发展出形形色色的 ...

  5. iOS绘图框架CoreGraphics分析

    由于CoreGraphics框架有太多的API,对于初次接触或者对该框架不是十分了解的人,在绘图时,对API的选择会感到有些迷茫,甚至会觉得iOS的图形绘制有些繁琐.因此,本文主要介绍一下iOS的绘图 ...

  6. 架构师之路(39)---IoC框架

    1 IoC理论的背景    我们都知道,在採用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,全部的对象通过彼此的合作,终于实现系统的业务逻辑.   图1:软件系统中耦合的对象 假设我 ...

  7. jQuery框架总体分析

    From:jQuery框架总体分析 jQuery的功能: 我们日常使用javascript干的最多的事情也就是 1.查找DOM节点 2.然后再对查找到的节点进行操作,例如修改样式 添加事件监听 修改内 ...

  8. Unity -- .NET下的原生Ioc框架

    摘自:http://www.cnblogs.com/tuyile006/archive/2011/04/07/2008642.html 偶然的机会,发现微软也出品Ioc框架了,属于Microsoft ...

  9. IOC框架---什么是IOC

    1 IoC理论的背景     我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑.                   ...

最新文章

  1. CSSE*PTC student tutoring program student lecturers of 2018-2019 Academic Year.
  2. 终于有了属于自己的家,哈哈,很高兴~~
  3. 怎么确定自己是第几层递归_递归(1)——理解递归思想
  4. xampp 无法启动mysql
  5. TensorFlow HOWTO 1.4 Softmax 回归
  6. ORA-01843 无效的月份的解决方法/NLS_DATE_FORMAT参数
  7. 编码规范系列(一):Eclipse Code Templates设置
  8. Python中的日期和时间
  9. brew源码安装mysql_mac使用brew安装mysql
  10. rapidxml学习记录
  11. urlrewrite配置
  12. tippy.js悬浮提示工具插件
  13. 凤凰网科技频道定位和主要内容
  14. vue根据表格字段不同的状态显示不同的颜色。
  15. 【改变思路】中式英语解决之法
  16. 遗传算法流程概述与简单实例认知
  17. Java+Swing+mysql用户信息管理系统
  18. 幂律分布(python)
  19. RRDTool中文手册
  20. LinkedIn领英怎么避免封号?封号怎么解决?(建议收藏)

热门文章

  1. 搜狗输入法电脑版_搜狗输入法上线墨水屏定制版
  2. as3 转义html,html和xml中的转义字符在Flash as3中的用法浅析
  3. 面向串口编程java_Java串口编程例子
  4. HDU-2191-悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(dp)
  5. NYOJ最长公共子序列(dp)
  6. 安装caffe时出现“MySQL”不是内外不wenjian
  7. QAbstractTableModel中的data()到底执行几遍???
  8. 05_DecisionTree_统计学习方法
  9. Intellij IDEA 2017 如何导入 GitHub 中的项目
  10. 6、Learn by doing才是正确的技术学习姿势