pureMVC一般流程通览小记

    目前,较主流Flex框架大致可分为两大类,一类是正规军MVC--Cairngorm&pureMVC,一类是自由军MVC兼IOC--swiz、mate、parsley、spring as。
    正规军的MVC是在既定模式下运作整个流程,而这个模式的形成是以解耦为原则的职责划分,优点自然是权责清晰,而其不足在于过于正规化使得工作量或效率被转嫁,一个看似小小的需求,也要动辄整个流程,使得小需求付出过多(即程序员编码量过大)。
    在这里,简单认识一下正规军中的pureMVC,认识她的一般处理流程、她的优缺点以及她可能的折中。

   pureMVC一般处理流程如下图:

pureMVC一般流程通览小记

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      特点:①MEDIATOR耦合VIEW在于解耦VIEW与其它部分的耦合性,通过MEDIATOR直接对VIEW数据收集与更新负责;
               ②MEDIATOR、COMMAND以及PROXY直接通过通知解耦,并合理完成后台调用后反馈数据更新;
     代价:①强松耦合加重通信次数;②带反馈数据的通信加重通信负担;
     折中:采用面向接口编程/依赖注入,变强松耦合为松耦合,同时可减少通信次数;

     接下来,用代码陈列的方式来感性认识pureMVC的一般处理流程(样例主线:model-view-mediator-command-proxy-other command):

Example

用户与View Component和Mediator的交互

假如有一个含表单的LoginPanel组件。对应有一个LoginPanelMediator,负责与LoginPanel交互并响应它的输入信息发送登录请求。
LoginPanel和LoginPanelMediator之间的协作表现为:LoginPanel在用户输入完信息要登录时发送一个TRY_LOGIN的事件,LoginPanelMediator处理这个事件,处理方法是发送一个以组件包含的LoginVO为“报体”的Notification(通知)。

LoginVO.as

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;//登录权限允许时服务器设置此值 
} 
} 

 
LoginPanel.mxml:

<?xml version="1.0" encoding="utf-8"?> 
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" 
title="Login" status=”{loginStatus}”> 
<!— 
The events this component dispatches. Unfortunately we can’t use 
the constant name here, because MetaData is a compiler directive 
--> 
<mx:MetaData> 
[Event('tryLogin')]; 
</mx:MetaData> 
<mx:Script> 
<![CDATA[ 
import com.me.myapp.model.vo.LoginVO; 
// 表单项与LoginVO对象的属性双向绑定。 
[Bindable] public var loginVO:LoginVO = new LoginVO(); 
[Bindable] public var loginStatus:String = NOT_LOGGED_IN; 
//义定Event名称常量 
public static const TRY_LOGIN:String='tryLogin'; 
public static const LOGGED_IN:String='Logged In'; 
public static const NOT_LOGGED_IN:String='Enter Credentials'; 
]]> 
</mx:Script> 
<mx:Binding source="username.text" destination="loginVO.username"/> 
<mx:Binding source="password.text" destination="loginVO.password"/> 
<!—The Login Form --> 
<mx:Form id="loginForm" > 
<mx:FormItem label="Username:"> 
<mx:TextInput id="username" text="{loginVO.username}" /> 
</mx:FormItem> 
<mx:FormItem label="Password:"> 
<mx:TextInput id="password" text="{loginVO.password}" 
displayAsPassword="true" /> 
</mx:FormItem> 
<mx:FormItem > 
<mx:Button label="Login" enabled="{loginStatus == NOT_LOGGED_IN}” 
click="dispatchEvent( new Event(TRY_LOGIN, true ));"/>
</mx:FormItem> 
</mx:Form> 
</mx:Panel> 

 


LoginPanel组件包含有一个用用户表单输入新创建的LoginVO对象,当用户单击“Login”按钮时触发一个事件,接下来的事情由LoginPanelMediator接管。
这样View Component的角色就是简单收集数据,收集完数据通知系统。
可以完善的地方是只有当username和password都有内容时才让login按钮可用(enable),这样可以避免恶意登录。
View Component对外隐藏自己的内部实现,它由Mediator使用的整个API包括:一个TRY_LOGIN事件,一个LoginVO属性和Panel的状态属性。
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 { 
  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;
 } 
} 
} 

 

注意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对象。

 

LoginCommand.as

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 ); 
} 
} 
} 

 

 LoginProxy.as

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.RESULT, onResult ); 
}
// 隐式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 
{ 
    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)。

 

GetPrefsCommand.as 

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; 
prefsProxy = facade.retrieveProxy( PrefsProxy.NAME ) as PrefsProxy; 
      prefsProxy.getPrefs( authToken ); 
} 
} 
} 

     由于此次给出的感性认识在于pureMVC的处理流程,因此,关于整个流程流转的配置略,若您有兴趣或者期望更进一步了解pureMVC,了解Mediator、Command、Proxy各自的职责等,可参见附件的那份中文文档或访问官网

你可能感兴趣的:(spring,编程,mvc,Flex,IOC)