转载地址:http://www.perfect-peak.com/blog/2011/03/13/puremvc/
PureMVC? 概述
- PureMVC 是什么?
PureMVC 是一个定位于设计高性能 RIA 客户端的基于模式的框架。目前已经被移植到多种语言(AS2、AS3、C#、ColdFusion、Haxe、JavaScript、Java、Objective C、PHP、Python、Ruby)和平台,包括服务器端环境。
- PureMVC 原理图示

- PureMVC 的两个版本
PureMVC 分为标准(Standard)和多核(MultiCore)两个版本。后者目的在于进行模块化编程。[PureMVC – Multicore vs Standard / Singlecore]介绍了两个版本的本质区别。
- PureMVC 教程
PureMVC Framework Goals and Benefits PureMVC Framework Overview with UML PureMVC Implementation Idioms and Best Practices PureMVC Implementation Idioms and Best Practices 简体中文(感谢张泽远和 Tamt 的翻译工作)
开始整合
- 注意事项:
以下内容基于“Flex4系列教程之九”中最后形成的 sampleApp 项目。
- 准备所需组件
下载?PureMVC(AS3) 多核版,将解压后的 PureMVC_AS3_MultiCore_1_0_5.swc 拷贝到 flex_libs 文件夹。
- 在 flex_src 下创建以下文件夹
employees employees/controller :放置 Command 类 employees/model :放置 Proxy 类 employees/view :放置 Mediator employees/view/components:放置视图文件(即 mxml 文件)
- 在继续之前,还是回顾一下 PureMVC 的原理吧
记住一点:PureMVC 的通信并不采用 Flash 的 EventDispatcher/Event,而是使用观察者模式以一种松耦合的方式来实现的。 所以要显示存储在数据库中的职员信息需经过以下过程:
- View Component 触发一个 Event;
- Mediator 监听到此 Event,发送通知;
- 控制器依据通知找到对应的 Command;
- Command 调用 Proxy(Proxy 又调用 Server 端对象),Proxy 依据执行结果发送相应通知;
- Mediator 接收到上诉通知,随即把通知中附带的雇员信息赋值给 DataGrid 组件。
- 不难理解,我们之所以创建 employees 文件夹就是要把雇员信息相关机能放到此文件下。
出于此目的我们把显示雇员信息的 DataGrid 组件从 sampleApp.mxml 中分离出来,命名为 EmployeesDataGrid,存储于 employees/view/components 下。
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="400" x="32" y="25">
<mx:DataGrid id="employeesList" width="400">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="name"/>
<mx:DataGridColumn headerText="Age" dataField="age"/>
<mx:DataGridColumn headerText="Email" dataField="email"/>
</mx:columns>
</mx:DataGrid>
</s:VGroup>
- 在 sampleApp 中引入 EmployeesDataGrid 组件
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600"
xmlns:view="employees.view.components.*">
<view:EmployeesDataGrid id="employeesDataGrid"/>
</s:Application>
- 在 employees 下创建 ApplicationFacade,作为此应用程序的 Facade
package employees
{
import org.puremvc.as3.multicore.patterns.facade.Facade;
import employees.controller.*;
public class ApplicationFacade extends Facade
{
public static const STARTUP:String = 'startup';
public function ApplicationFacade(key:String) {
super(key);
}
public static function getInstance(key:String):ApplicationFacade {
if (instanceMap[key] == null)
instanceMap[key] = new ApplicationFacade(key);
return instanceMap[key] as ApplicationFacade;
}
override protected function initializeController():void {
super.initializeController();
registerCommand(STARTUP,StartupCommand);
}
public function startup(app:sampleApp):void {
sendNotification(STARTUP,app);
}
}
}
[注:]看到上面的 StartupCommand 了吧,我们稍候创建它,该 Command 主要用于注册 Proxy 和 Mediator。
- 在主应用中初始化 Facade,并调用 startup 方法(应该能理解调用此方法的意图吧?)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600"
xmlns:view="employees.view.components.*"
initialize="facade.startup(this);">
<fx:Script>
<![CDATA[
import employees.ApplicationFacade;
public static const NAME:String = 'sampleApp';
private var facade:ApplicationFacade = ApplicationFacade.getInstance(NAME);
]]>
</fx:Script>
<view:EmployeesDataGrid id="employeesDataGrid"/>
</s:Application>
- 是时候创建 StartupCommand 了
package employees.controller
{
import org.puremvc.as3.multicore.patterns.command.SimpleCommand;
import org.puremvc.as3.multicore.interfaces.INotification;
public class StartupCommand extends SimpleCommand
{
override public function execute(note:INotification):void {
// @TODO
}
}
}
- 至此 pureMVC 已经整合完毕,是不是很简洁?:) 接下来实现雇员信息输出。
- 首先在 model 下创建 LoadEmployeesProxy,调用远程对象返回雇员信息
package employees.model
{
import org.puremvc.as3.multicore.patterns.proxy.Proxy;
import mx.rpc.remoting.RemoteObject;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
public class LoadEmployeesProxy extends Proxy {
public static const NAME:String = 'LoadEmployeesProxy';
public static const LOAD_EMPLOYEES_SUCCESS:String = 'loadEmployeesSuccess';
public static const LOAD_EMPLOYEES_FAILED:String = 'loadEmployeesFailed';
private var employeeServiceRO:RemoteObject;
public function LoadEmployeesProxy() {
super(NAME);
employeeServiceRO = new RemoteObject();
employeeServiceRO.destination = "employeeServiceDest";
employeeServiceRO.addEventListener(ResultEvent.RESULT,onResult);
employeeServiceRO.addEventListener(FaultEvent.FAULT,onFault);
}
public function load():void {
employeeServiceRO.getList();
}
private function onResult(event:ResultEvent):void {
sendNotification(LOAD_EMPLOYEES_SUCCESS,event.result);
}
private function onFault(event:FaultEvent):void {
sendNotification(LOAD_EMPLOYEES_FAILED,event.fault.faultString);
}
}
}
- 其次在 view 下创建管理 EmployeesDataGrid 的 Mediator — EmployeesDataGridMediator
package employees.view
{
import org.puremvc.as3.multicore.patterns.mediator.Mediator;
import org.puremvc.as3.multicore.interfaces.INotification;
import flash.events.Event;
import mx.controls.Alert;
import employees.ApplicationFacade;
import employees.model.LoadEmployeesProxy;
import employees.view.components.EmployeesDataGrid;
public class EmployeesDataGridMediator extends Mediator
{
public static const NAME:String = 'EmployeesListMediator';
public function EmployeesDataGridMediator(viewComponent:EmployeesDataGrid) {
super(NAME,viewComponent);
employeesDataGrid.addEventListener(EmployeesDataGrid.LOAD_EMPLOYEES,onGetEmployees);
}
protected function onGetEmployees(event:Event):void {
sendNotification(ApplicationFacade.LOAD_EMPLOYEES);
}
override public function listNotificationInterests():Array {
return [
LoadEmployeesProxy.LOAD_EMPLOYEES_SUCCESS,LoadEmployeesProxy.LOAD_EMPLOYEES_FAILED
];
}
override public function handleNotification(note:INotification):void {
switch (note.getName()) {
case LoadEmployeesProxy.LOAD_EMPLOYEES_SUCCESS:
employeesDataGrid.employeesList.dataProvider = note.getBody();
break;
case LoadEmployeesProxy.LOAD_EMPLOYEES_FAILED:
Alert.show(note.getBody().toString(),'Error');
break;
}
}
protected function get employeesDataGrid():EmployeesDataGrid {
return viewComponent as EmployeesDataGrid;
}
}
}
- 把上面创建的 Proxy 和 Mediator 注册到 Model 和 View 中
package employees.controller
{
import org.puremvc.as3.multicore.patterns.command.SimpleCommand;
import org.puremvc.as3.multicore.interfaces.INotification;
import employees.model.LoadEmployeesProxy; import employees.view.EmployeesDataGridMediator;
public class StartupCommand extends SimpleCommand
{
override public function execute(note:INotification):void {
facade.registerProxy(new LoadEmployeesProxy()); var app:sampleApp = note.getBody() as sampleApp; facade.registerMediator(new EmployeesDataGridMediator(app.employeesDataGrid));
}
}
}
[注:]在注册 Mediator 的时候也就确定了它所管理的 Mxml 文件
- 在 controller 中创建 LoadEmployeesCommand,用于调用 LoadEmployeesProxy
package employees.controller
{
import org.puremvc.as3.multicore.patterns.command.SimpleCommand;
import org.puremvc.as3.multicore.interfaces.INotification;
import employees.model.LoadEmployeesProxy;
public class LoadEmployeesCommand extends SimpleCommand
{
override public function execute(note:INotification):void {
var loadEmployeesProxy:LoadEmployeesProxy =
facade.retrieveProxy(LoadEmployeesProxy.NAME) as LoadEmployeesProxy;
loadEmployeesProxy.load();
}
}
}
- 把 LoadEmployeesCommand 与事件的对应关系追加到 ApplicationFacade 中
package employees
{
import org.puremvc.as3.multicore.patterns.facade.Facade;
import employees.controller.*;
public class ApplicationFacade extends Facade
{
public static const STARTUP:String = 'startup';
public static const LOAD_EMPLOYEES:String = 'loadEmployees';
public function ApplicationFacade(key:String) {
super(key);
}
public static function getInstance(key:String):ApplicationFacade {
if (instanceMap[key] == null)
instanceMap[key] = new ApplicationFacade(key);
return instanceMap[key] as ApplicationFacade;
}
override protected function initializeController():void {
super.initializeController();
registerCommand(STARTUP,StartupCommand);
registerCommand(LOAD_EMPLOYEES,LOADEmployeesCommand);
}
public function startup(app:sampleApp):void {
sendNotification(STARTUP,app);
}
}
}
- 万事俱备,只需要在 EmployeesDataGrid 创建完毕时触发相应事件
<?xml version="1.0" encoding="utf-8"?>
<s:VGroup xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="400" x="32" y="25"
creationComplete="init();">
<fx:Metadata>
[Event('loadEmployees')]
</fx:Metadata>
<fx:Script>
<![CDATA[
public static const LOAD_EMPLOYEES:String = 'loadEmployees'; public function init():void { dispatchEvent(new Event(LOAD_EMPLOYEES,true)); }
]]>
</fx:Script>
<mx:DataGrid id="employeesList" width="400">
<mx:columns>
<mx:DataGridColumn headerText="Name" dataField="name"/>
<mx:DataGridColumn headerText="Age" dataField="age"/>
<mx:DataGridColumn headerText="Email" dataField="email"/>
</mx:columns>
</mx:DataGrid>
</s:VGroup>
- 运行试试吧 :)
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|