ROBOTLEGS轻量级AS3框架

Robotlegs是一个用来开发FlashFlexAIR应用的纯AS3微架构(框架)Robotlegs专一于将应用程序各层排布在一块儿并提供它们相互通信的机制。Robotlegs试图经过提供一种解决常见开发问题的通过时间检验的架构解决方案来加速开发。Robotlegs无心锁定你到框架,你的类就是你的类的样子,并且应该很容易地切换到其余框架。 git

框架提供一个基于Model-View-Controller元设计模式的默认实现。这个实现提供一个针对应用程序结构和设计的强烈建议。虽然它确实轻微减低了你的应用程序的便携性,不过它依然以最低限度影响你的具体类为目标。经过扩展MVCS实现类,你能够得到不少有用的方法和属性。 github

你没必要使用Robotlegs的标准MVCS实现。你可使用它的任意部分,或者彻底不使用它,或者使用本身的实现来适应你的需求。它是为了提供合适的参考实现和快速开始使用Robotlegs而被包含进来。 web

目录 数据库

1.      MVC 编程

1.1.       MVC分解 设计模式

1.2.       消息通讯、依赖注入等 架构

2.      ROBOTLEGS与其它框架的比较 mvc

3.      ROBOTLEGS的依赖注入 app

3.1.       依赖注入 框架

3.2.       SwiftSuspenders

SwiftSuspenders 适配器注入语法

4.      ROBOTLEGS的标准MVCS实现

4.1.       Robotlegs MVC+S

4.2.       推荐目录结构

4.3.       Context

提供根视图(root-view

调用startup()方法

4.4.       Command

Command 职责

触发 Command

应用程序层的解耦

4.5.       View & Mediator

Mediator 职责

映射一个 Mediator

访问一个 Mediator  View Component

给一个 Mediator 添加事件监听

监听框架事件

广播框架事件

监听 View Component 事件

经过 Mediator 访问 Model  Service

4.6.       Models

Model 职责

映射一个 Model

从一个Model里广播事件

4.7.       Services

Service 职责

映射一个 Service

广播框架事件

在一个 Service 里解析数据

Service 事件

5.      扩展点

参考文献

 

 

1.  MVC

clip_image002

MVC就是(Model View Controller)模型-视图-控制器,是一个设计模式(也能够称为架构模式),但目前在大部分人眼里显然并不仅有这点意义。受到各类MVC框架的影响,消息通讯,依赖注入,隔离编译等等概念如今都加入到了MVC的概念里,并且由于应用上的重叠和类似性,还经常和三层架构的概念混淆。

“一千我的眼中有一千个哈姆雷特”

一个名词的意义,是由人们的理解来决定的,所以这里从最基本的概念入手。

1.1.     MVC分解

对于一个用于显示的程序,最开始,只有View(视图)。

咱们要得到一个数据并显示,就是写段代码调用接口,得到数据,而后根据数据更新视图。而这里的数据只是一个临时变量,或者存在于视图的某个属性中。显然,这样作的话,数据是依赖于视图的,若是不经过视图,或者视图根本不存在的时候,其余模块就访问不到这个已经返回的数据,则须要从新调用一次,这显然是一种浪费,并且也不便利。所以咱们在这里将数据保存到别处,和视图不共享同一辈子命周期,那么这分离出来的数据则被规定为Model(模型)。

(在这里我必须打断说明下,模型!=数据,仅仅是在这个简化例子里模型==数据。模型是为视图提供内容的单独模块,具体内部是什么状况则是各类各样的,提供数据只是它的功能之一)

至此,就是最基本的分离表现层的原则。然而,有个地方倒是分不开的——原来控制加载数据的这部分代码。它负责的是获取数据,并指示视图根据数据更新的任务,而它的去向有两个选择:要不加到视图上(这是一般的作法),要不加在模型上(若是须要模型对应多个视图),反正他不可能由于分离就凭空消失。那么咱们把这部分代码提出来做为单独的部分,就是Controller(控制器)。

一旦分离出了控制器,联系模型和视图的具体代码就再也不处于二者之上(固然调用代码仍是有的),而是一个独立的部分。它有本身的名字,并且不会和其余不相关的内容混合在一块儿,很是清晰,容易定位。而模型和视图今后也只关心控制器,而不关心对方。他们的代码都是处理本身的事情,别人的事情所有交给控制器去办,这使得他们本身的功能也很是独立,减小了须要考虑的要素。

这只是代码位置的移动,可是这样移动后,将牵涉内容最多最易变,可是代码量最少的代码单独放入控制器中,并妥善管理。至关与将分散在房间各处的开关集中于一处,排列整齐并标注名字,作成遥控器在手里把玩,今后就能从奔波于房间各个位置,寻找隐藏在角落里的小突起的平常活动中解放出来。其意义,不言而喻。

而这,做为MVC的做用,已经足够了。

1.2.     消息通讯、依赖注入等

一旦咱们将视图,模型,控制器分离后,能够作到什么呢?

由于视图和模型都只用处理本身的事情,对控制器的调用只是一句代码而已,那么,它们实际上就能够被隔离出去。负责这部分代码的人只须要关心本身的事情,而不须要关心整个环境。一样的,编写控制器的人只须要知道视图和模型的对外接口,而不须要了解它们的具体实现,也就是只须要关心环境。这使得不一样开发者须要的知识被分隔开,每人只须要了解有限的少许知识,最终却又能顺利合并在一块儿。

这是就是协做分工的基础。

在这以后,三者的关系只存在简单的调用代码。那么为了可以完全的分离和解耦,就能够将调用代码改成发送消息或者其余的动态形式,这样就能在没有其余部分的时候独立编译。由不一样人在不一样的工做环境独立完成本身的部分,并在最后发布时候简单合并在一块儿,这确实是最理想的协做模式。

作到这点须要一个消息框架,而这就是MVC框架的主要任务。除此以外,各类不一样的框架还会加入其它设计模式,提供各类附加功能,自动依赖注入就是其中一项。还可能加入其它的中间件,进一步分割层次,诸如分离出视图其中的逻辑部分,使得绘图和位置代码不会和逻辑代码混合,方便分工以及修改。使用观察者模式,使得数据部分的修改能够自动同步到视图上,如此这般……MVC框架指的是“实现MVC的框架”,而非“只实现MVC的框架”,仅仅实现MVC,这个框架的功能太过贫乏了,毕竟MVC也就是那种程度的东西。

最终,完成了这些以后,就成为了通常人表面看到的东西。虽然各式各样,咱们都将其称之为“MVC框架”。

2.  RobotLegs与其它框架的比较

下面对比下比较热门的几个as3框架:

Framework

Dependencies Management

Event Management

Presentation Pattern

Cairngorm

Singleton

Singleton Dispatcher

Code Behind

PureMVC

Service Locator

Notification

Mediator

Mate

Dependency Injection

Display list

Presentation Model

Swiz

Dependency Injection

Display list

Presentation Model

Parsley

Dependency Injection

Central Dispatcher

Presentation Model

Robotlegs

Dependency Injection

Event bus

Mediator or others

pureMVCCairngorm是两个较早出现的框架,目前我不建议再使用它们。pureMVC的问题在于过于强调分离而缺少实际功能,提供的便利很难抵消它自己的消耗,性价比较低。Cairngorm的问题则在于过于强调模型更新视图的流程,限制太多,灵活程度不够。

后出的几个框架就好多了,Mate使用了一个全局事件定义,配合FLEX写法很是简略。Swiz则是用控制反转+依赖注入,也就是Spring的作法,并且元标签注入的方式颇有趣,感兴趣的可自行查阅资料。

RobotLegs是一个和Swiz很是类似的框架,但也有一些本身的特色。RobotLegs它是基于pureMVC的,能够像pureMVC这样来使用它,对于使用pureMVC的团队它是很容易接受的代替品。pureMVC是基于Notification的一个MVC框架,主要目的是为了各个部分可以解耦,固然它也基本上可以作到。RobotLegs则是基于消息以及消息携带的数据等来实现解耦。RobotLegs是基于pureMVC的思想,可是在一些方面更加出色,例如消息的强类型依赖注入方式,消息携带数据等等。

robotlegs里使用了flash的事件机制来通讯,而puremvc使用自定的通知来发消息。这里区别不大,只是使用事件机制就得写事件类;而后robotlegs使用自动mediator自动注册,它靠侦听addtostage来处理,固然,手动注册也是容许的。这样方便了很多,puremvc只能手动在视图组件初始化时注册,并且有时有些内部组件常常会出现未初始化完成时就去注册,致使访问不到this。还有最重要的依赖注入,robotleg再也不使用puremvc那样的传递参数方法,而是使用依赖注入,包括mediatorview组件的引用都是注入的。这样依赖性又小了不少,感受很是不错。

我的认为RobotlegspureMVC好用,RobotlegspureMVC的改进升级版并且是专一于as3的,注入技术更是省去了pureMVC的许多麻烦。

3.  RobotLegs的依赖注入

RobotLegs使用了如下3个面向对象设计模式:

ü  自动依赖注入(Automated Dependency Injection,不用对象本身建立、获取依赖的对象,而是由容器/框架来完成。

ü  命令模式(Command Pattern

n  命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开;

n  每个命令都是一个操做:请求的一方发出请求,要求执行一个操做;接收的一方收到请求,并执行操做。

n  命令模式容许请求的一方和接收的一方独立开来,使得请求的一方没必要知道接收请求的一方的接口,更没必要知道请求是怎么被接收,以及操做是否被执行、什么时候被执行,以及是怎么被执行的。

ü  调度者模式(Mediator Pattern,定义一个中介对象来封装系列对象之间的交互。中介者使各个对象不须要显示地相互引用,从而使其耦合性松散,并且能够独立地改变他们之间的交互。

Robotlegs围绕依赖注入设计模式展开。最简单地,依赖注入是为对象提供实例变量或属性的行为。

当你传递一个变量到一个类的构造函数,你在使用依赖注入;

当你设置一个类的属性,你在使用依赖注入;

若是你不是使用严格的过程或线性方式编写AS3,极可能你如今就在使用依赖注入。

Robotlegs使用基于元数据的自动依赖注入。这是为了方便开发而提供,并且在排布应用程序并提供类和它所须要的依赖时,能够减小不少代码量。虽然彻底能够手动提供这些依赖,可是容许框架来履行这些职责能够减小出错的机会,而且一般能够加快编码进程。

3.1.        依赖注入

依赖注入(Dependency Injection,简称DI),是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。依赖注入还有一个名字叫作控制反转(Inversion of Control,英文缩写为IoC)。依赖注入是这样一个过程:因为某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,因此客户类只定义一个注入点。在程序运行过程当中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境专门组件负责实例化服务类,而后将其注入到客户类中,保证客户类的正常运行。即对象在被建立的时候,由一个运行上下文环境或专门组件将其所依赖的服务类对象的引用传递给它。也能够说,依赖被注入到对象中。因此,控制反转是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转

clip_image004

l  依赖注入使用如下三种基本技术:

n  类型1 (基于接口): 可服务的对象须要实现一个专门的接口,该接口提供了一个对象,能够从用这个对象查找依赖(其它服务)

n  类型2 (基于setter): 经过属性的setter方法为可服务对象指定服务。

n  类型3 (基于构造函数): 经过构造函数的参数为可服务对象指定服务。

不要重复发明轮子!

对于应用频繁的需求,老是有人设计各类通用框架和类库以减轻人们的开发负担。例如,数据持久化是很是频繁的需求,因而各类ORM框架应运而生;再如,对MVC的需求催生了Struts等一批用来实现MVC的框架。

随着依赖注入变成了很是频繁的需求,而若是所有手工完成,不但负担过重,并且还容易出错。再加上反射机制的发明,因而,天然有人开始设计开发各类用于依赖注入的专用框架。这些专门用于实现依赖注入功能的组件或框架,就是IoC Container

IOC关注服务(或应用程序部件)如何定义的以及他们应该如何定位他们依赖的其它服务。因此一般,经过一个容器或定位框架(著名的Spring容器、)来得到定义和定位的分离,容器或定位框架负责:

l  保存可用服务的集合

l  提供一种方式将各类部件与它们依赖的服务绑定在一块儿

l  为应用程序代码提供一种方式来请求已配置的对象(例如,一个全部依赖都知足的对象), 这种方式能够确保该对象须要的全部相关的服务均可用。

 

3.2.        SwiftSuspenders

Robotlegs采用一种适配器(adapter)机制来为框架提供依赖注入机制。默认地,框架配备了SwiftSuspenders注入/反射库来适合这个要求。另有SmartyPants-IoC  Spring Actionscript 的适配器可使用。可能有潜在的特定需求来使用其它的依赖注入适配器,可是若是没有特别的理由,建议使用默认的SwiftSuspenders,由于它为 Robotlegs 作了一些特别调整。

clip_image006

SwiftSuspenders 适配器注入语法

SwiftSuspenders 支持三种类型的依赖注入:

ü  属性()注入

ü  参数(方法/设值注入

ü  构造注入

咱们将特别介绍属性注入,以及在 Robotlegs 里如何使用。将属性注入类有两种选择,你可使用未命名,或命名的注入:

[Inject]

public var myDependencyDepedency; //未命名注入

[Inject(name="myNamedDependency")]

public var myNamedDependencyNamedDepedency; //命名注入

Robotlegs里三处提供了注入映射:MediatorMapCommandMap、直接经过InjectorMediatorMapCommandMap也都是使用Injector,但它们同时作了一些各自层(tier)所须要的额外工做。顾名思义,MediatorMap用来映射MediatorCommandMap用来映射Command;其它全部须要被注入的内容 (包括但不限于 Model) 都要直接使用 Injector 映射。

Injector 类的映射注入

具体 Injector 类的适配器都遵守 IInjector 接口。 这个接口为不一样的依赖注入解决方案提供了统一的API 本文专一于 SwiftSuspenders,但这些语法一样适应于其它任何遵守 Iinjector 接口的 Injector

Injector是你应用程序里所发生的全部依赖注入的生产车间。它用来注入框架 actor,同时也能够用来执行你的应用程序所须要的任何其它注入。这包括但不限于 RemoteObjectsHTTPServices,工厂类,或者事实上任何有可能成为你的对象所须要的依赖的类/接口。

下面是实现 IInjector 接口的类所提供的四个映射方法:

clip_image008

MediatorMap 类的依赖注入

MediatorMap 实现 IMediatorMap 接口。 IMediatorMap 提供两个方法来将你的 mediators 映射到 view 并注册它们以便用来注入。

mapView(viewClassOrName*mediatorClassClassinjectViewAsClass = nullautoCreateBoolean = trueautoRemoveBoolean = true)void

mapView 接受一个视图类,MyAwesomeWidget,或者一个视图的类全名,com.me.app.view.components::MyAwesomeWidget 做为第一个参数。 第二个参数是将要做为视图组件中介的 Mediator 类。 [injectViewAs 内容未完成],最后的两个参数 autoCreate  autoRemove 提供方便的自动管理 mediator 的布尔值开关。

//在你的程序里某个映射/配置发生的地方

mediatorMap.mapView(MyAwesomeWidgetMyAwesomeWidgetMediator);

//conntextView 的显示列表里的某个地方

var myAwesomeWidget:MyAwesomeWidget = new MyAwesomeWidget();

this.addChild(myAwesomeWidget); // ADDED_TO_STAGE 事件被抛出,触发这个视图组件的中介机制

这个方法使用了自动中介机制。

CommandMap 类的依赖注入

CommandMap 类实现 ICommandMap 接口,提供一个用来将 command 映射到到触发它们的框架事件的方法。

mapEvent(eventTypeStringcommandClassClasseventClassClass = nulloneshotBoolean = false)

你要提供给 commandMap 一个能够执行的类,执行它的事件类型,可选的这个事件的强类型,以及这个 command 是否只被执行一次而且随即取消映射的布尔值开关。

这个可选的强类型事件类用来对Flash平台的"magic string"事件类型系统作额外的保护。以免采用相同事件类型字符串的不一样事件类之间的冲突。

//在你的程序里某个映射/配置发生的地方

commandMap.mapEvent(MyAppDataEventDATA_WAS_RECEIVEDMyCoolCommandMyAppDataEvent);

//在事件被广播的另一个框架actor

//这触发了随后被执行的被映射的 command

dispatch(new MyAppDataEvent(MyAppDataEvent.DATA_WAS_RECEIVEDsomeTypedPayload))

4.  Robotlegs的标准MVCS实现

Robotlegs提供了一个比较规范的MVC+SModel模型,View视图,Controller控件和Service服务)实现,来帮助开展工做。经过将几个通过时间检验的设计模式整合到一个具体实现, Robotlegs  MVCS 实现能够用作建立你的应用程序的一致方案。 经过这些架构概念着手一个应用程序, 你甚至能够在开始你的设计以前避免不少常见的障碍:

ü  分离:MVCS 提供一种将你的应用程序分离到提供特定功能的无关联的层的很天然的方法。 view 层处理用户交互。 model 层处理用户建立的或从外部获取的数据。 controller 提供一种封装各层之间复杂交互的机制。 最后, service 层提供一种和外界(好比远程服务 API 或文件系统)交互的独立机制。

ü  组织:经过这种分离咱们天然得到一个组织水平。 每一个项目都须要某个组织水平。 是的,有人能够把他们全部的类都扔到顶级包下完事,但即便是最小的项目这也是不可接受的。 当一个项目有了必定的规模就须要开始组织类文件的结构了。 当向同一个应用程序开发中增长团队成员的时候问题就更加严重了。 RobotLegs  MVCS 实现为项目描绘出一个分为四层的优雅的组织结构。

ü  解耦:Robotlegs MVCS实现将应用程序解耦为4层。 每层都与其它层隔离, 使分离类和组件分别测试变得很是容易。除了简化测试进程, 一般也使类更具便携性以在其它项目中使用。 好比, 一个链接到远程 API  Service 类可能在多个项目中都颇有用。 经过解耦这个类, 它能够不需重构便从一个项目转移到另外一个中使用。

4.1.        Robotlegs MVC+S

一个典型的Robotlegs MVC+S应用程序包含如下几个部分:

clip_image010

ü  Context:所谓Context(上下文),其实是一套自展机制,用来初始化Robotlegs所使用的依赖注入以及各类核心工具。

ü  Commands:所谓Commands(命令),表明的是应用程序所能执行的独立操做。一般,Commands(命令)会做为对用户操做的反应,但命令的做用并不只限于此。

ü  Mediators:所谓Mediators(中介),是用来管理应用程序中的视图组件与应用程序中的其它对象之间的信息交流。

ü  ModelModels(模型)中保存着数据信息,而且表现出应用程序当前的状态。

ü  ServiceServices(服务),是应用程序与外界的接口。

下面用用互操做view到获得响应的一个流程图:

clip_image012

 

4.2.        推荐目录结构

Robotlegs代码包结构组织:

[domain.lib]

    various utilities

[domain.project]

    [projectmodule]

        [model]

            [events]

            [vo]

            ProjectModuleStateModel

        [view]

            [events]

            [renderers]

            [skins]

            MyProjectModuleView

            MyProjectModuleViewMediator

        [controller]

            [startup]

            MyProjectModuleActionCommand

        [service]

            [helpers]

            MyProjectModuleService

            IProjectModuleService

        [signals]

    [projectmodule]

        [model]

            [events]

            [vo]

            ProjectModuleStateModel

        [view]

            [events]

            [renderers]

            [skins]

            MyProjectModuleView

            MyProjectModuleViewMediator

        [controller]

            [startup]

            MyProjectModuleActionCommand

        [service]

            [helpers]

            MyProjectModuleService

            IProjectModuleService

        [signals]

    

这是Joel Hooks建议的包结构。这是一个多模块状况的包结构,若是是单模块,能够少去projectmodule这一层。[signals]包不是必须的,除非你用到了Signals

把每一个模块要都用到的公共代码放到[domain.lib]下。模块和模块内代码保证独立,不会相互使用(引用,实例化)。

StartupCommand内代码建议以MVC结构分离。若是一个模块中StartupCommnad内有过多代码,建议把它拆分红ModelStartupCommandControllerStartupCommandViewStartupCommand,这样职责更清晰。

[controller][view]中,若是有不少类,建议按照功能创建子目录。

4.3.        Context

其实是一套自展机制,用来初始化Robotlegs所使用的依赖注入以及各类核心工具,一个应用程序是能够有多个 context 的,这对想要加载外部模块的应用程序颇有用,由于在一个 context 里的 actor 只能在他们的 context 定义的范围以内相互通信,因此在一个模块化的应用程序里,不一样context 之间的通信是彻底可能的。

每个Robotlegs项目都以Context开始,只有Context实例化以后,Robotlegs才能启动和运行。建立Context须要给提供一个根视图并调用startup()方法。

提供根视图(root-view

每一个Rogotlegs应用程序须要一个根视图——DisplayObjectContainter的一个实例。它将供mediatorMap使用,因此当子视view图添加到根视图时,对应的mediator会被建立并和view关联起来。

调用startup()方法

启动应用程序须要在全部配置都准备好以后,而后调用startup()方法来启动。能够经过将autoStartup:Boolean=true,而后该方法会自动被调用;又或者将autoStartup:Boolean=false,而后手动调用startup()方法。

startup()方法中会初始化依赖注入规则!若是规则不多,能够所有写在这个该方法中;不然,建议分离到不一样的配置类中。

4.4.        Command

Controller 层由 Command 类体现(一个Command是一个简明、单一目的的控制器controller对象)。Command是短生命周期的无状态对象。它们在被实例化和执行以后当即释放。Command 应该只在处理框架事件时被执行,而不该该被任何其余框架 actor 实例化或执行。

clip_image014

Command 职责

Command 用于应用程序各层之间相互通信,也可能用来发送系统事件。这些系统事件既可能发动其它的 Command 也可能被一个 Mediator 接收,而后对一个 View Component 进行对应这个事件的工做。

Command  Context  CommandMap 注册到 ContextCommandMap  Context  Command 类里默承认用。Command 类被注册到 Context 时接收4个参数一个事件类型响应这个事件时执行的 Command 可选的事件类一个是否该 Command 只被执行一次随即被取消注册而不响应后续事件触发的一次性设置.

触发 Command

Command  MediatorsServicesModels,和其它 Command 广播的框架事件触发。一个被映射的 command 在响应一个框架事件时被实例化,全部已被映射,并被 [Inject] 元数据标签标记过的依赖都会被注入到这个 Command。另外,触发这个 Command 的事件实例也会被注入。当这些依赖被注入完毕,Command 的执行方法会被自动调用,Command 便会进行它的工做。你不须要,并且不该该直接调用 execute() 方法。这是框架的工做。

应用程序层的解耦

Command 是解耦一个应用程序里各个 actor 的很是有用的机制。由于一个 Command 永远不会被 MediatorModel 或者 Service 实例化或执行,这些类也就不会被耦合到 command,甚至都不知道 command 的存在.

为了履行它们的职责,Command 可能:

ü  映射 MediatorModelService,或者 Context 里的其它 Command

ü  广播可能被 Mediator 接收或者触发其它 Command 的事件.

ü  被注入ModelService,和Mediator 以直接进行工做.

须要注意的是,不建议在一个 Command 里直接和 Mediator 交互。虽然这是可行的,但会将这个 Mediator 耦合到这个 Command。由于 Mediator 不像Service  Model,它能够接受系统事件,更好的作法是让 Command 广播事件,而后让须要响应这些事件的 Mediator 监听它们。

 

4.5.        View & Mediator

View  Mediator 类体现。继承 Mediator 的类管理应用程序中的 View Component 与应用程序中的其它对象之间的信息交流。一个Mediator 将会监听框架事件和 View Component 事件,并在处理所负责的 View Component 发出的事件时发送框架事件。这样开发者能够将应用程序特有的逻辑放到Mediator,而避免把 View Component 耦合到特定的应用程序。

注意,Mediator仅仅是框架和View Component之间的桥梁,这也是他惟一的职责。

clip_image016

Mediator 职责

一个 View Component 是任何的UI组件和/或它的子组件。一个 View Component 是已被封装的,尽量多地处理本身的状态和操做。一个 View Component 提供一个包含了事件,简单方法和属性的APIMediators负责表明它所中介的View Component和框架交互。这包括监听组件及其子组件的事件,调用其方法,和读取/设置组件的属性.

一个 Mediator 监听它的 View Component 的事件,经过 View Component 暴露的 API 访问其数据。一个 Mediators 经过响应其它框架 actor 的事件并对本身的 View Component 进行相应修改来表明它们。一个 Mediator 经过转发 View Component 的事件或本身向框架广播合适的事件来通知其它的框架 actor.

映射一个 Mediator

任何能够访问到mediatorMap实例的类均可以映射 Mediator。这包括 MediatorContext,和 Command .

这是映射一个 mediator 的语法:

mediatorMap.mapView( ViewClassMediatorClassautoCreateautoRemove );

view添加到舞台上时,Mediator会被自动建立并关联起来。

clip_image018

view从舞台上移除时,Mediator会被自动清除。

clip_image020

访问一个 Mediator  View Component

当一个 View Component 在一个 Context  contextView 里被添加到舞台上的时候,它默认地会被根据 MediatorMap 作映射时的配置被自动关联。在一个基本的 mediator 里,viewComponent会被注入为被中介的 view component。一个 Mediator viewComponent属性是 Object 类型的。在大多数状况下,咱们但愿访问一个强类型的对象以从中获益。为此目的,咱们注入被中介的 view component 的强类型实例:

public class GalleryLabelMediator extends Mediator implements IMediator

{

      [Inject]

      public var myCustomComponent:MyCustomComponent;

            

      /**

      覆写 onRegister 是添加此 Mediator 关心的任何系统或 View Component 事件的好机会.

      */

      override public function onRegister():void

      {

             //添加一个事件监听器到 Context 来监听框架事件

             eventMap.mapListener( eventDispatcherMyCustomEvent.DO_STUFFhandleDoStuff );

             //添加一个事件监听器到被中介的 view component

             eventMap.mapListener( myCustomComponentMyCustomEvent.DID_SOME_STUFFhandleDidSomeStuff)

      }

     

      protected function handleDoStuff(event:MyCustomEvent):void

      {

             //把事件的强类型负载设置到 view component 的属性。

             //View component 极可能基于这个新数据管理本身的状态.

             myCustomComponent.aProperty = event.payload

      }

     

      protected function handleDidSomeStuff(event:MyCustomEvent):void

      {

             //把这个事件转发到框架

             dispatch(event)

      }

}

经过这种方法咱们如今能够很方便地访问被中介的 view component 的公开属性和方法.

给一个 Mediator 添加事件监听

事件监听器是 Mediator 的眼睛和鼻子。由于框架内的全部通信都经过原生的Flash事件,Mediator 能够经过添加事件监听器来响应感兴趣的事件。除了框架事件,Mediator同时监听所中介的 view component 的事件.

一般在 Mediator  onRegister 方法里添加事件监听。在 Mediator 生命周期中的这个阶段,它已经被注册而且它的 view component 和其它依赖也都已被注入。具体的 Mediator 类必须覆写 onRegister 方法。也能够在其它方法里添加事件监听,好比响应框架事件和 view component 事件的事件处理方法里.

Mediators 装备了一个有 mapListener() 方法的 EventMap。这个方法注册每一个被添加到 Mediator 的事件监听,而且确保 mediator 被框架取消注册时删除这些事件监听。Flash 里删除事件监听是很重要的,由于若是一个类里添加了事件监听而没有删除,Player将没法对此类进行运行时垃圾回收(GCGarbage Collection)。也可使用传统的 Flash 语法添加事件监听器,但要注意也要手动把它们删除。

clip_image022

监听框架事件

全部框架里的actor在实例化时都会被注入一个eventDispatcher属性。这个eventDispatcher就是 Mediator 发送和接受框架事件的机制.

eventMap.mapListener(eventDispatcherSomeEvent.IT_IS_IMPORTANThandleFrameworkEvent)

经过此语法,一个 Mediator 如今监听了SomeEvent.IT_IS_IMPORTANT事件并在handleFrameworkEvent方法里处理它。

广播框架事件

Mediator的一个很重要的职责就是向框架发送其它 actor 可能感兴趣的事件。这些事件一般是在响应应用程序用户和被中介的 view component 之间的一些交互时发出的。这里一样有一个能够减小发送事件到框架的代码输入的颇有用的方法:

dispatch(new SomeEvent(SomeEvent.YOU_WILL_WANT_THISmyViewComponent.someData))

这个事件如今能够被其它 Mediator 接收或者执行一个 command 了。发出事件的 Mediator 并不关心其它的 actor 如何回应这个事件,它只是简单地广播一条有事发生的消息。一个 mediator 也能够监听本身发出的事件,而后据此做出回应.

监听 View Component 事件

Mediator 负责所中介的 view component 发出的事件。这能够是个独立组件,好比 TextField 或者 Button,也能够是有嵌套层级的复杂组件。当 mediator收到 view component 发出的事件会使用指定的方法处理它。和框架事件同样,EventMap  mapListener 方法是给一个 mediator 添加事件监听的首选.

eventMap.mapListener(myMediatedViewComponentSomeEvent.USER_DID_SOMETHINGhandleUserDidSomethingEvent)

响应一个 view component 的事件时,一个 mediator 可能:

ü  考察事件的 负载payload   (若是有)数据

ü  考察 view component 的当前状态

ü  view component 进行须要的工做

ü  发送系统事件以通知其它actor有事发生

经过 Mediator 访问 Model  Service

你的 mediator 能够监听 Service  Model 类派出的系统事件来提升松耦合性。经过监听事件,你的 mediator 不须要关心事件来源,而只需直接使用事件携带的强类型的 负载payload 数据。所以,多个 mediator 能够监听相同的事件而后根据所收到的数据调整本身的状态.

在一个 mediator 里直接访问 service 能够提供很大便利而不会带来严重的耦合性问题。一个 service 并不存储数据,只是简单地提供一个向外部service发送请求并接受响应的API。可以直接访问这个API能够避免在你的应用程序中增长不须要的 command 类来达到一样目的。若是这个 service API 在不少mediator 中经过相同的方式访问,将此行为封装到一个 command 里有益于保持此行为的一致性并减小对此 service 的反复调用以及在你的 mediator 里的直接访问.

建议经过 model  service 实现的接口将 model  service 注入 mediator

访问其它 Mediator

如同 Service  Model,在一个 Mediator 里也能够注入和访问其它的 Mediator。这种作法是 强烈不建议的 由于这种紧耦合能够简单地经过使用框架事件进行通信而避免。

 

4.6.        Models

Model 类用来管理对应用程序的数据模型的访问。Model 为其它框架actor提供一个 API 来访问,操做和更新应用程序数据。这个数据包括但不限于原生数据类型好比 StringArray,或者像 ArrayCollection 同样的域特有对象或集合.

Model 有时被当作简单的 Model 好比 UserModel,有时也被当作 Proxy 好比 UserProxy。在 Robotlegs 里,这两种命名都是用做相同的目的,为应用程序数据提供一个 API。无论采用哪一种命名 model 都继承提供了核心框架依赖和一些有用方法的 Actor 基类。

Model 会在对数据模型进行某些工做以后发出事件通知。Model 一般具备极高的便携性。

Model 职责

Model类封装了应用程序数据模型并为其提供一个 API。一个 Model 类是你的应用程序数据的看门人。应用程序里的其它 actor 经过 Model 提供的API 请求数据。由于数据是经过 Model 更新,Model 装备了向框架广播事件的机制以向其它 actor 通知数据模型的变化使它们得以据此调整本身的状态.

除了控制对数据模型的访问,Model 一般也被用来保证数据状态的有效性。这包括对数据进行计算,或域特有逻辑的其它领域。Model 的这个职责很是重要。Model 是应用程序中最有潜力具备便携性的层。经过把域逻辑放入 Model,之后的 model 实现就再也不须要像把域逻辑放入 View  Controller层那样重复这些相同的逻辑,做为一个例子,你的 Model 里可能执行购物车数据的计算。一个 Command 将会访问这个方法,最终的计算结果将会被做为被某个 Mediator 监听的事件派发出去。这个 mediator 将会根据这个被更新的数据更新本身的 view component,应用程序的第一个迭代是个典型的Flex 程序。这个计算也很容易在一个 Mediator 甚至视图里进行。应用程序的第二个迭代是一个须要全新视图元素的移动设备 Flash 应用程序。由于这个逻辑在 Model 里,因此能够很容易被两个彻底不一样元素的视图复用.

映射一个 Model

Injector 有几个方法能够用来将你的 Model 类映射到你的框架actor。另外,这些方法事实上能够用来注入任何类到你的类里.

将一个已存在的实例当作一个单例注入映射,使用下面的语法:

injector.mapValue(MyModelClassmyModelClassInstance)

为每一个注入映射一个类的新实例,使用下面的语法:

injector.mapClass(MyModelClassMyModelClass)

另外,这也能够用来使用被注入的实现某接口的合适的类来映射这个用来注入的接口.

injector.mapClass(IMyModelClassMyModelClass)

为某个接口或类映射一个单例实例,使用下面的语法:

injector.mapSingleton(MyModelClassMyModelClass)

须要注意重要的一点,当说起上面的一个单例时,它并非一个单例模式的单例。在这个 Context 以外并不强制它做为一个单例。Injector 简单地确保这个类的惟一一个实例被注入。这对处理你的应用程序数据模型的 Model 很是重要.

从一个Model里广播事件

Model 类提供一个方便的dispatch方法用来发送框架事件:

dispatch( new ImportantDataEvent(ImportantDataEvent.IMPORTANT_DATA_UPDATED))

有不少理由派发一个事件,包括但不限于:

ü  数据已被初始化并准备好被其它 actor 使用

ü  一些数据片被添加到 Model

ü  数据被从 Model 中删除

ü  数据已改变或者更新

ü  数据相关的状态已改变

在一个 Model 里监听框架事件

虽然技术上可能,但强烈不建议这样作。不要这样作。只是为了说清楚:不要这样作。若是你这样作了,不要说你没被警告过.

4.7.        Services

Service 用来访问应用程序范围以外的资源。这包括但固然不限于:

ü  web services

ü  文件系统

ü  数据库

ü  RESTful APIs

ü  经过 localConnection 的其它 Flash 应用程序

Service 封装了这些和外部实体的交互,并管理这个交互产生的 result fault 或其它事件.

你可能注意到 Service  Model 的基类很是相像。事实上,你可能注意到除了类名,它们实际上是同样的。那么为何用两个类呢? Model  Service 类在一个应用程序里有彻底不一样的职责。这些类的具体实现将再也不相像。若是没有这个分离,你将常常发现 Model 类在访问外部服务。这让 Model 有不少职责,访问外部数据,解析结果,处理失败,管理应用程序数据状态,为数据提供一个 API,为外部服务提供一个 API,等等。经过分离这些层有助于缓解这个问题。

clip_image024

Service 职责

一个 Service 类为你的应用程序提供一个和外部服务交互的 API。一个 service 类将链接外部服务并管理它收到的响应。Service 类一般是无状态的实体。他们并不存储从外部服务收到的数据,而是发送框架事件来让合适的框架 actor 管理响应数据和失败.

映射一个 Service

injector 的多个可用的方法能够用来映射你的 Service 类以注入你的其它框架 actor。另外,这些方法也能够用来注入事实上任何类到你的类里。

将一个已存在的实例当作一个单例注入映射,使用下面的语法:

injector.mapValue(MyServiceClassmyServiceClassInstance)

为每一个注入映射一个类的新实例,使用下面的语法:

injector.mapClass(MyServiceClassMyServiceClass)

另外,这也能够用来使用被注入的实现某接口的合适的类来映射这个用来注入的接口.

injector.mapClass(IMyServiceClassMyServiceClass)

为某个接口或类映射一个单例实例,使用下面的语法:

injector.mapSingleton(MyServiceClassMyServiceClass)

须要注意重要的一点,当说起上面的一个单例时,它并非一个单例模式的单例。在这个 Context 以外并不强制它做为一个单例。Injector 简单地确保这个类的惟一一个实例被注入.

在一个 Service 里监听框架事件

虽然技术上可能,但 强烈不建议 这样作。不要这样作。只是为了说清楚不要这样作。若是你这样作了,不要说你没被警告过.

广播框架事件

Service 类提供一个方便的dispatch方法用来发送框架事件:

dispatch( new ImportantServiceEvent(ImportantServiceEvent.IMPORTANT_SERVICE_EVENT))

在一个 Service 里解析数据

从外部获取到的数据并不符合咱们应用程序的 context。它们是外来者。能够围绕外部数据类型对应用程序进行建模,或者更可取地,转换这些数据以符合应用程序。应用程序里有两处能够进行这项操做/转换。Service  Model 都很适合。Service 是进入外部数据的第一个点,因此它是操做一个外部服务返回的数据的更好的选择。外来数据应该在第一个机会转换到应用程序域。

提供一个使用工厂类而不是在 service 里生成应用程序域对象的例子… 适当的

当数据被转换为应用程序域特有的对象以后发出带有强类型负载的事件以被对此关心的 actor 当即使用.

Service 事件

service 组合的最后一个部分是自定义事件。没有事件的 service 只是哑吧。他们可能作的任何工做都不会被其它框架成员注意到。一个 service 将会使用自定义事件来向应用程序发出声音。事件并不必定是惟一的意图。若是这个 service 正在转换数据它可使用一个普通的事件来派发强类型的数据给感兴趣的应用程序 actor

5.  扩展点

l  Robotlegs配合as3signal使用,替代flash原生事件机制。采用as3signal能够有效减小View-Mediator的事件对象,其效率高于事件机制。

下面是flash原生机制与as3signal的性能测试对比(http://alecmce.com/as3/events-and-signals-performance-tests),测试环境:I found the following results on Mac OS X, Flash Player 10.0.42.34, with a release build.

When an event (signal) is dispatched but nothing is listening for it:

clip_image025

When an event (signal) is dispatched and handled by one method listener:

clip_image026

 

l  Robotlegs多模块开发。Robotlegs提供一个多模块工具:robotlegs-utilities-Modular。能够方便的进行模块和模块之间的通讯。它看上去十分优雅,用起来也十分方便。下面是几点要注意的地方:

n  尽可能将模块内事件和模块间的事件分开,不要混杂着用,用于区分它们。

n  全部须要公用的对象或类(VOModelService)都在主模块的Startup时注入,这样子模块均可以很方便的用到。

clip_image027http://joelhooks.com/2010/05/02/modular-robotlegs/

l  在添加大量Sprite到舞台前,能够设置:mediatorMap.enabled=false;。完成后再设置为true,这样能够避免MediatorMap侦听到ADDED_TO_STAGE事件后频繁进行没必要要的操做。也可使用Robotlegs  LazyMediator 扩展。

为了游戏中有更好的性能eidiot Robotlegs 写了一个 LazyMediator 扩展。(https://github.com/eidiot/robotlegs-utilities-LazyMediator

如何使用

n   context  override mediatorMap  getter 方法:

return _mediatorMap || (_mediatorMap = new LazyMediatorMap(contextView, injector));

n   view 类的构造函数里增长:

new LazyMediatorActivator(this);

做用

n  LazyMediatorMap 不监听显示列表里全部的 ADDED_TO_STAGE 事件而检测全部被添加到显示列表的显示对象。

如何工做

n   view 被添加到 stage 或从 stage 移除时 LazyMediatorActivator 广播 LazyMediatorEvent

n  LazyMediatorMap 监听 context  LazyMediatorEvent 而后检查对应的 view

相关文章
相关标签/搜索