Flex框架 - PureMVC中文技术文档


实现 术语阐述 及 最佳实践 用 PureMVC 创建健壮、易扩展、易维护的客户端程序 附 ActionScript 3 及 MXML 实例 作者 翻译: 张泽远 <51ajax.net@gmail.com> Tamt 最后更新: 5/19/2008 : Cliff Hall PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 2 of 44 5/20/2008 11:17 PM PureMVC 结构 4 • Model 与 Proxy 4 • View 与 Mediator 4 • Controller 与 Command 4 • Façade 与 Core 5 • Observer 与 Notification 5 • Notification可以被用来触发Command的执行 5 • Mediator发送、声明、接收Notification 6 • Proxy发送,但不接收Notification 6 Façade 7 • 具体Façade是什么样子的? 7 • 为程序创建Façade 7 • 初始化Façade 10 Notification 12 • Event与Notification 12 • 定义Notification和Event常量 13 Command 14 • SimpleCommand和MacroCommand的使用 15 • 降低Command与Mediator, Proxy的耦合度 15 • 复杂的操作与业务逻辑 16 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 3 of 44 5/20/2008 11:17 PM Mediator 21 • Mediator的职责 21 • 转化View Component类型 22 • 监听并响应View Component 23 • 在Mediator里处理Notification 25 • Mediator和Proxy之间、Mediator和其他Mediator之间的耦合 27 • 用户与View Component和Mediator的交互 28 Proxy 33 • Proxy的职责 34 • 转换数据对象 34 • 避免对Mediator的依赖 36 • 封装域逻辑 37 • 与Remote Proxy通信 38 启示 PureMVC 是一个定位于设计高性能 RIA 客户端的基于模式 的框架。现在它已经被移植到其他的平台上,包括服务器 端环境。本篇文档论述针对于客户端。 PureMVC 在不同平台语言下的阐述、实现,PureMVC 所 使用的模式在“四人帮”的《设计模式:可复用面向对象 软件的基础》一书中有很好的论述。 强烈推荐。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 4 of 44 5/20/2008 11:17 PM PureMVC 结构 PureMVC框架的目标很明确,即把程序分为低耦合的三层:Model、View和 Controller。 降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用 程序是非常重要的。 在PureMVC实现的经典MVC元设计模式中,这三部分由三个单例模式类管理,分 别是Model、View和Controller。三者合称为核心层或核心角色。 PureMVC中还有另外一个单例模式类——Façade,Façade提供了与核心层通信 的唯一接口,以简化开发复杂度。 Model 与 Proxy Model 保存对 Proxy 对象的引用,Proxy 负责操作数据模型,与远程服务通 信存取数据。 这样保证了 Model 层的可移植性。 View 与 Mediator View 保存对 Mediator 对象的引用 。由 Mediator 对象来操作具体的视图组 件(View Component,例如 Flex 的 DataGrid 组件),包括:添加事件监 听器 ,发送或接收 Notification ,直接改变视图组件的状态。 这样做实现了把视图和控制它的逻辑分离开来。 Controller 与 Command Controller 保存所有 Command 的映射。Command 类是无状态的,只在需 要时才被创建。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 5 of 44 5/20/2008 11:17 PM PureMVC 结构 Controller 与 Command Command 可以获取 Proxy 对象并与之交互,发送 Notification,执行其他 的 Command。经常用于复杂的或系统范围的操作,如应用程序的“启动”和 “关闭”。应用程序的业务逻辑应该在这里实现。 Façade 与 Core Façade 类应用单例模式,它负责初始化核心层(Model , View 和 Controller),并能访问它们的 Public 方法。 这样,在实际的应用中,你只需继承 Façade 类创建一个具体的 Façade 类就 可以实现整个 MVC 模式,并不需要在代码中导入编写 Model,View 和 Controller 类。 Proxy、Mediator 和 Command 就可以通过创建的 Façade 类来相互访问通 信。 Observer 与 Notification PureMVC 的通信并不采用 Flash 的 EventDispatcher/Event ,因为 PureMVC 可能运行在没有 Flash Event 和 EventDispatcher 类的环境中, 它的通信是使用观察者模式以一种松耦合的方式来实现的。 你可以不用关心 PureMVC 的 Observer/Notification 机制是怎么实现的,它 已经在框架内部实现了。你只需要使用一个非常简单的方法从 Proxy, Mediator, Command 和 Facade 发送 Notification,甚至不需要创建一个 Notification 实例。 Notification可以被用来触发Command的执行 Facade 保存了 Command 与 Notification 之间的映射。当 Notification(通知)被 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 6 of 44 5/20/2008 11:17 PM PureMVC 结构 Notification可以被用来触发Command的执行 发出时,对应的 Command(命令)就会自动地由 Controller 执行。Command 实 现复杂的交互,降低 View 和 Model 之间的耦合性。 Mediator发送、声明、接收Notification 当用 View 注册 Mediator 时,Mediator 的 listNotifications 方法会被调用, 以数组形式返回该 Mediator 对象所关心的所有 Notification。 之后,当系统其它角色发出同名的 Notification(通知)时,关心这个通知的 Mediator 都会调用 handleNotification 方法并将 Notification 以参数传递到 方法。 Proxy发送,但不接收Notification 在很多场合下 Proxy 需要发送 Notification(通知),比如:Proxy 从远程服 务接收到数据时,发送 Notification 告诉系统;或当 Proxy 的数据被更新时, 发送 Notification 告诉系统。 如果让 Proxy 也侦听 Notification(通知)会导致它和 View(视图)层、 Controller(控制)层的耦合度太高。 View 和 Controller 必须监听 Proxy 发送的 Notification,因为它们的职责是 通过可视化的界面使用户能与 Proxy 持有的数据交互。 不过对 View 层和 Controller 层的改变不应该影响到 Model 层。 例如,一个后台管理程序和一个面向用户程序可能共用一个 Model 类。如果只 是用例不同,那么 View/Controller 通过传递不同的参数就可以共用相同的 Model 类。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 7 of 44 5/20/2008 11:17 PM Façade MVC 元设计模式的核心元素在 PureMVC 中体现为 Model 类、View 类和 Controller 类。为了简化程序开发,PureMVC 应用了 Façade 模式。 Façade 是 Model、View 和 Controller 三者的“经纪人”。实际编写代码时你 并不用导入这三者的类文件,也不用直接使用它们。Façade 类已经在构造方法包 含了对核心 MVC 三者单例的构造。 一般地,实际的应用程序都有一个 Façade 子类,这个 Façade 类对象负责初始 化 Controller(控制器),建立 Command 与 Notification 名之间的映射,并执 行一个 Command 注册所有的 Model 和 View。 具体Façade是什么样子的? Façade 类应被当成抽象类, 永远不被直接实例化。针对具体的应用程序,你应 该具体编写 Façade 的子类,添加或重写 Façade 的方法来实现具体的应用。 按照惯例,这个类命名为“ApplicationFacade”(当然,命名随你喜欢), 如前所述,它主要负责访问和通知 Command,Mediator 和 Proxy。 通常,不同的运行平台都会创建视图结构,尽管创建过程不一样。(比如 Flex 中 MXML 程序负责实例化所有子视图组件,Flash 影片在 Stage 上构建可视 对象)。视图结构构建完毕时,整个 PureMVC 机制也已经安置妥当。 创建的 Facade 子类也被用来简化“启动”的过程。应用程序调用 Facade 子 类的 startup 方法,并传递自身的一个引用即完成启动,使得应用程序不需要 过多了解 PureMVC。 为程序创建Façade Façade 类的内容很简单。思考下面的例子: PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 8 of 44 5/20/2008 11:17 PM Façade 为程序创建Façade ApplicationFacade.as: package com.me.myapp { import org.puremvc.as3.interfaces.*; import org.puremvc.as3..patterns.facade.*; import com.me.myapp.view.*; import com.me.myapp.model.*; import com.me.myapp.controller.*; // MyApp 程序的 Façade 类 public class ApplicationFacade extends Façade implements IFacade { //定义 Notification(通知)常量 public static const STARTUP:String = "startup"; public static const LOGIN:String = "login"; //得到 ApplicationFacade 单例的工厂方法 public static function getInstance() : ApplicationFacade { if ( instance == null ) instance = new ApplicationFacade( ); return instance as ApplicationFacade; } //注册 Command,建立 Command 与 Notification 之间的映射 override protected function initializeController( ) : void { super.initializeController(); registerCommand( STARTUP, StartupCommand ); PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 9 of 44 5/20/2008 11:17 PM Façade 为程序创建Façade registerCommand( LOGIN, LoginCommand ); registerCommand( LoginProxy.LOGIN_SUCCESS, GetPrefsCommand ); } //启动 PureMVC,在应用程序中调用此方法,并传递应用程序本身的引用 public function startup( app:MyApp ) : void { sendNotification( STARTUP, app ); } } } 上述代码需要注意以下几点: o ApplicationFacade 继承自 PureMVC 的 Façade 类,Façade 类实现了 IFacade 接口。 o 这个例子里 ApplicationFacade 没有重写构造方法 。如果重写 构造方法,应该在构造方法里先调用父类的构造方法。 o 类方法 getInstance 用于返回 ApplicationFacade 的单例,并 将实例保存在父类的一个 protect 变量中。在返回该实例之前必 须先把它转化为 ApplicationFacade 类型。 o 定义了 Notification 名称常量。Façade 类是整个系统其他角色相互 访问通信的核心,所以在这里定义 Notification(通知)名称常量 是最合适的。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 10 of 44 5/20/2008 11:17 PM Façade 为程序创建Façade o 初始化 Controller(控制器),并建立 Command 与 Notification 之 间的映射,当 Notification(通知)发出时相关的 Command(命 令)就会被执行。 o 提供一个带有应用程序类型参数的 startup 方法,该参数能过 Notification 传递到 StartupCommand。 实现这些只需要继承父类很少的功能。 初始化Façade PureMVC 的 Façade 类在构造方法中初始化了 Model、View 和 Controller 对象,并把对它们的引用保存在成员变量。 这样,Façade 就可以访问 Model、View 和 Controller 了。这样把对核心 层的操作都集中在 Façade,避免开发者直接操作核心层。 那么,在具体的应用程序中,Façade 是何时何地初始化的呢?请查看下面的 Flex 代码: MyApp.mxml: [Event('tryLogin')]; PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 30 of 44 5/20/2008 11:17 PM Mediator 用户与 View Component 和 Mediator 的交互 LoginPanel 组件包含有一个用用户表单输入新创建的 LoginVO 对象,当用 户单击“Login”按钮时触发一个事件,接下来的事情由 LoginPanelMediator 接管。 这样 View Component 的角色就是简单收集数据,收集完数据通知系统。 可以完善的地方是只有当 username 和 password 都有内容时才让 login 按钮可用(enable),这样可以避免恶意登录。 View Component 对外隐藏自己的内部实现,它由 Mediator 使用的整个 API 包括:一个 TRY_LOGIN 事件,一个 LoginVO 属性和 Panel 的状态属 性。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 31 of 44 5/20/2008 11:17 PM Mediator 用户与 View Component 和 Mediator 的交互 LoginPanelMediator 会对 LOGIN_FAILED 和 LOGIN_SUCCESS 通知做出反应, 设置 LoginPanel 的状态。 LoginPanelMediator.as: package com.me.myapp.view { import flash.events.Event; import org.puremvc.as3.interfaces.*; import org.puremvc.as3.patterns.mediator.Mediator; import com.me.myapp.model.LoginProxy; import com.me.myapp.model.vo.LoginVO; import com.me.myapp.ApplicationFacade; import com.me.myapp.view.components.LoginPanel; // LoginPanel视图的Mediator public class LoginPanelMediator extends Mediator implements IMediator { public static const NAME:String = 'LoginPanelMediator'; public function LoginPanelMediator( viewComponent:LoginPanel ) { super( NAME, viewComponent ); LoginPanel.addEventListener( LoginPanel.TRY_LOGIN, onTryLogin ); } // 列出该Mediator关心的Notification override public function listNotificationInterests( ) : Array { PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 32 of 44 5/20/2008 11:17 PM Mediator 用户与 View Component 和 Mediator 的交互 return [ LoginProxy.LOGIN_FAILED, LoginProxy.LOGIN_SUCCESS ]; } // 处理Notification override public function handleNotification( note:INotification ):void { switch ( note.getName() ) { case LoginProxy.LOGIN_FAILED: LoginPanel.loginVO = new LoginVO( ); loginPanel.loginStatus = LoginPanel.NOT_LOGGED_IN; break; case LoginProxy.LOGIN_SUCCESS: loginPanel.loginStatus = LoginPanel.LOGGED_IN; break; } } // 户单击用 Login 钮尝试录按, 登。 private function onTryLogin ( event:Event ) : void { sendNotification( ApplicationFacade.LOGIN, loginPanel.loginVO ); } // 把viewComponent转类化成它真正的 型。 protected function get loginPanel() : LoginPanel { return viewComponent as LoginPanel; PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 33 of 44 5/20/2008 11:17 PM Mediator 用户与 View Component 和 Mediator 的交互 } } } 注意 LoginPanelMediator 在构造方法中给 LoginPanel 注册了一个侦听方 法——onTryLogin,当用户单击 Login 按钮时这个方法会被执行。在 onTryLogin 方法里发送了一个 LOGIN 的 Notification(通知,携带参数 LoginVO 对象)。 早先(在 ApplicationFacade 中)我们已经把 LoginCommand 注册到这 个 Notification 上了。LoginCommand 会调用 LoginProxy 的“登录”方法, 传参 LoginVO。LoginProxy 把“登录”请求远程服务,之后发送 LOGIN_SUCCESS(登录成功)或 LOGIN_FAILED(登录失败)的 Notification。这些类的定义请参见“Proxy”章节。 LoginPanelMediator 把 LOGIN_SUCCESS 和 LOGIN_FAILED 注册 自己的关心 的 Notification ,当这两个 Notification 被发送时,Mediaotr 作为响应把 LoginPanel 的 loginStatus 设置为 LOGGED_IN (登录成功时)或 NOT_LOGGED_IN(登录失败时),并清除 LoginVO 对象。 Proxy 一般来说,Proxy Pattern(代理模式)被用来为控制、访问对象提供一个代理。在 基于 PureMVC 的应用程序,Proxy 类被设计用来管理程序数据模型。 一个 Proxy 有可能管理对本地创建的数据结构的访问。它是 Proxy 的数据对象。 在这种情况下,通常会以同步的方式取得或设置数据。Proxy 可能会提供访问 Data Object 部分属性或方法的 API,也可能直接提供 Data Object 的引用。如果提供了更 新 Data Object 的方法,那么在数据被修改时可能会发送一个 Notifidation 通知系统 的其它部分。 Remote Proxy 被用来封装与远程服务的数据访问。Proxy 维护那些与 Remote service (远程服务)通信的对象,并控制对这些数据的访问。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 34 of 44 5/20/2008 11:17 PM Proxy 在这种情况下,调用 Proxy 获取数据的方法,然后等待 Proxy 在收到远程服务的数 据后发出异步 Notification。 Proxy 的职责 Proxy 封装了数据模型,管理 Data Object 及对 Data Object 的访问,不 管数据来自哪里,什么类型。 在 PureMVC 中,Proxy 是个被 Model 注册的简单的数据持有者。 虽然 Proxy 类已经是完全可用的了,但是通常对于具体的应用你应该编写 Proxy 的子类,增加操作方法。 通常 Proxy Pattern 有以下几种类型: o Remote Proxy, 当 Proxy 管理的数据存放在远程终端,通过 某种服务访问。 o Proxy and Delegate, 多个 Proxy 共享对一个服务的访问, 由 Delegate 封装对服务的控制访问,确保响应正确的返回给 相应的请求者。 o Protection Proxy, 用于数据对象的访问有不同的权限时。 o Virtual Proxy, 对创建开销很大的数据对象进行管理。 o Smart Proxy, 首次访问时载入数据对象到内存,并计算它被 引用的次数,允许锁定确保其他对象不能修改。 转换数据对象 Proxy 基类的构造方法接受一个名称(name)和一个 Object 类型的参数,Object 类 型的参数用来设置 Proxy 管理的数据模型,在构造方法完成后也可以调用 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 35 of 44 5/20/2008 11:17 PM Proxy 转换数据对象 setData 方法来设置。 就像 Mediator 和它的 View Component 一样,为了访问它的属性和方法, 你会经常需要把这个 Data Object 转化成它真正的类型。看起来只是重复繁 琐了一些,但更严重的是可能会暴露过多的 Data Object 细节。 另外,因为 Data Object 通常是一个复杂的数据结构,我们经常需要引用它 的一部分属性并将类型转化成我们需要的数据。 再一次的,ActionScript 语言支持隐式的 getter 和 setter 属性,它可以很好地帮 助我们解决这种频繁的类型转换问题。 一个很好的惯用做法是在你具体的 Proxy 类中引入一个适当命名的隐式 getter,用来把 Data Object 转化它真正的类型。 另外,可能需要定义不同的多个类型 getter 来取得 Data Object 某部分的数 据。 比如: public function get searchResultAC () : ArrayCollection { return data as ArrayCollection; } public function get resultEntry( index:int ) : SearchResultVO { return searchResultAC.getItemAt( index ) as SearchResultVO; } PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 36 of 44 5/20/2008 11:17 PM Proxy 转换数据对象 在别的 Mediator 中,我们不用再这样做了: var item:SearchResultVO = ArrayCollection ( searchProxy.getData() ).lastResult.getItemAt( 1 ) as SearchResultVO; 而可以这样: var item:SearchResultVO = searchProxy.resultEntry( 1 ); 避免对 Mediator 的依赖 Proxy 不监听 Notification,也永远不会被通知,因为 Proxy 并不关心 View 的状态。但是,Proxy 提供方法和属性让其它角色更新数据。 Proxy 对象不应该通过引用、操作 Mediator 对象来通知系统它的 Data Object(数据对象)发生了改变。 它应该采取的方式是发送 Notification(这些 Notification 可能被 Command 或 Mediator 响应)。Proxy 不关心这些 Notification 被发出后会影响到系统 的什么。 把 Model 层和系统操作隔离开来,这样当 View 层和 Controller 层被重构时 就不会影响到 Model 层。 但反过来就不是这样了:Model 层的改变很难不影响到 View 层和 Controller 层。毕竟,它们存在的目的就是让用户与 Model 层交互的。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 37 of 44 5/20/2008 11:17 PM Proxy 封装域逻辑 Model 层中的改变总会造成 View/Controller 层的一些重构。 我们把 Domain Logic(域逻辑)尽可能放在 Proxy 中实现,这样尽可能地 做到 Model 层与相关联的 View 层、Controller 层的分离。 Proxy 仅仅 对 访问 对不 用来管理数据 象的 ,而且用来封装数据 象的操作使得 维态数据 持在一个合法的状 。 比如, 算 税是一个计营业 (域逻辑),它 放在应该 中Domain Logic Proxy 实现而不是 Mediator 或 Command。 虽然可以放在任意一个中实现,但是把它放在 Proxy 中实现不仅仅是出于逻 辑(logic)上的考虑,这样做还可以保持其它层更轻便、更易被重构。 一个 Mdeiator 可能获取(retrieve)这个 Proxy 对象;调用它的营业税计 算方法,传参一些表单项目数据。如果把真正的计算放在 Mediator 的话, 就是把 Domain Logic(域逻辑)嵌在 View 层了。对营业税的计算是 Domain Model(域模型)中的一条规则。View 仅仅是把它看成 Domain Model 的一个属性,当用户的输入正确这个属性对 View 就可用。 假设你现在正在工作的程序项目是一个嵌在浏览器中桌面级的 RIA 解决方案。 但新的版本可能是简化了用例(use case)的嵌在 PDA 中的解决方案,但 仍然完全需要当前程序项目的 Model 层。 如果已经有正确的分离操作,我们就可以完全重用 Model 层而只需开发新的 View 层和 Controller 层。 虽然把对营业税的计算放在 Mediator 上看起来很有效而且在写代码时也很 容易;你可能只需要把营业税计算出来交给 Model 而已。 然而你却需要在程序的不同版本中重复的付出,在每个新的 View 层复制粘贴 营业税计算逻辑,所以最好把这段逻辑放在 Model 层。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 38 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 Remote Proxy 对象是一个从远程位置(Remote location)获取 Data Object 的 Proxy。这通常意味着我们与它的交互是以异步的方式。 Proxy 获取数据的方式取决于客户端平台、远程服务(remote service) 的实现和开发人员的选择。在 Flash/Flex 环境中,我们可能会使用 HTTPService,WebService,RemoteObject,DataService 或者 XMLSocket 来从 Proxy 中发送服务请求。 根据需要,Remote Proxy 可能动态的发送请求,响应时会设置一个属性或 调用一个方法; 或只在构造方法中发送一次请求,然后提供访问数据的 get/set 方法。 在 Proxy 中有很多东西可以优化以提高与远程服务通信的效率。 比如:缓存(服务器返回的)数据以减少网络通信的“废话”;只发送改变的 数据,减少带宽的浪费。 如果请求是由系统其它角色动态调用 Remote Proxy 的方法而发出的,那 Proxy 在结果返回来时应该发送一个 Notification。 注意关心这个 Notification 的角色有可能并不是发起这个数据请求的那个角色。 举例,调用远程服务的查询并显示返回的结果,这个过程通常会有以下几步: o 一个 View Component 触发一个事件发起一个查询请求。 o 它的 Mediator 响应:获取相应的 RemoteProxy,设置它的 searchCriteria 属性。 o Proxy 的 searchCriteria 属性其实是一个隐式 setter,它会保存 赋值,通过内部的 HTTPService(它会侦听 result 和 fault 事 件)初始查询请求。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 39 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 o 当服务返回结果时,HTTPService 会触发 ResultEvent 事件, Proxy 响应,把结果保存在公共属性中。 o Proxy 然后发送一个 Notification 表示请求成功,这个 Notification 会绑定一个对数据对象的引用作为“报体”。 o 关心这个 Notification 的另外一个 Mediator 就会响应这个 Notification,把“报体”中的数据赋值给它所操作的 View Component 的 dataProvider 属性。 再来,假设有一个 LoginProxy,它有一个 LoginVO(一个 Value Object;简单 的数据载体类)。LoginVO 可能看起来像这样: package com.me.myapp.model.vo { //把这个AS3 VO映射到Remote Class [RemoteClass(alias="com.me.myapp.model.vo.LoginVO")] [Bindable] public class LoginVO { public var username: String; public var password: String; public var authToken: String;//登录权限允许时服务器设置此值 } } LoginProxy 对设录录外提供方法 置登 数据,登 (logging in),退出(logging out 获), 取“ 录登 ”时权标识用到的 限 。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 40 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 LoginProxy: package com.me.myapp.model { import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.remoting.RemoteObject; import org.puremvc.as3.interfaces.*; import org.puremvc.as3.patterns.proxy.Proxy; import com.me.myapp.model.vo.LoginVO; // 用于用户登录的Proxy public class LoginProxy extends Proxy implements IProxy { public static const NAME:String = 'LoginProxy'; public static const LOGIN_SUCCESS:String = 'loginSuccess'; public static const LOGIN_FAILED:String = 'loginFailed'; public static const LOGGED_OUT:String = 'loggedOut'; private var loginService: RemoteObject; public function LoginProxy () { super( NAME, new LoginVO ( ) ); loginService = new RemoteObject(); loginService.source = "LoginService"; loginService.destination = "GenericDestination"; loginService.addEventListener( FaultEvent.FAULT, onFault ); loginService.login.addEventListener( ResultEvent.RESUL T, onResult ); } PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 41 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 // 隐式getter,转化data的类型 public function get loginVO( ) : LoginVO { return data as LoginVO; } //如果logivVO中包含了authToken(授权标识)表示用户登录成功 public function get loggedIn():Boolean { return ( authToken != null ); } // 取得authToken public function get authToken():String { return loginVO.authToken; } // 置用的限设 户权标识,登录,退出,或 登继续尝试 录。 public login( tryLogin:LoginVO ) : void { if ( ! loggedIn ) { loginVO.username= tryLogin.username; loginVO.password = tryLogin.password; } else { logout(); login( tryLogin ); } } // 退出, 地清空简单 LoginVO public function logout( ) : void PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 42 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 { if ( loggedIn ) loginVO = new LoginVO( ); sendNotification( LOGGED_OUT ); } //通知系登成功统录 private function onResult( event:ResultEvent ) : void { setData( event.result ); // immediately available as loginVO sendNotification( LOGIN_SUCCESS, authToken ); } //通知系登失统录败 private function onFault( event:FaultEvent) : void { sendNotification( LOGIN_FAILED, event.fault.faultString ); } } } 一个 LoginCommand 会获取 LoginProxy,设置登录的数据,调用登录函 数,呼叫登录服务。 接下来,可能一个 GetPrefsCommand 会响应 LOGIN_SUCCESS(登录成 功)这个 Notification,从 Notificaiton 的“报体”中获取 authToken(授权 标识),接着呼叫下一个服务,获取用户的(比如)配置信息 (preferences)。 PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 43 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 LoginCommand: package com.me.myapp.controller { import org.puremvc.as3.interfaces.*; import org.puremvc.as3.patterns.command.*; import com.me.myapp.model.LoginProxy; import com.me.myapp.model.vo.LoginVO; public class LoginCommand extends SimpleCommand { override public function execute( note: INotification ) : void { var loginVO : LoginVO = note.getBody() as LoginVO; var loginProxy: LoginProxy; loginProxy = facade.retrieveProxy( LoginProxy.NAME ) as LoginProxy; loginProxy.login( loginVO ); } } } GetPrefsCommand: package com.me.myapp.controller { import org.puremvc.as3.interfaces.*; import org.puremvc.as3.patterns.command.*; import com.me.myapp.model.LoginProxy; import com.me.myapp.model.vo.LoginVO; public class GetPrefsCommand extends SimpleCommand { override public function execute( note: INotification ) : void { var authToken : String = note.getBody() as String; var prefsProxy : PrefsProxy; PureMVC 是 Futurescale 公司创建并维护的开源自由的程序框架。Futurescale, Inc. Copyright © 2006-08, Some rights reserved。使用 PureMVC 必须遵守美国 Creative Commons 3.0 Attribution 协议。PureMVC、本文档以及任何从 Futurescale 网站下载的文档、培训资料及示例代码,都不提供任何明示或者默示的担保,包括但是不限于是否符合特定的 目的、未侵害他人权利的担保。 Page 44 of 44 5/20/2008 11:17 PM Proxy 与 Remote Proxy 通信 prefsProxy = facade.retrieveProxy( PrefsProxy.NAME ) as PrefsProxy; prefsProxy.getPrefs( authToken ); } } }
还剩43页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

hot00123

贡献于2011-08-23

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf