在PureMVC 学习笔记(一)中介绍了一个《flex框架pureMVC的使用:第一步》(后简称:第一步)的例子,此文关于PureMVC的介绍非常生动明了,如果想快速学习PureMVC这个framework的话,建议看一下。
不过其中所举例子对于想要自己动手使用PureMVC的人就稍显不足了。因为《第一步》对于代码的介绍是从application启动加载Facade开始的,然后注册Command,Proxy,Mediator,这样的说明的好处是快速让读者理解PureMVC内部运行机制。在理解了PureMVC的原理之后,我们就要开始构思怎样对一个工程应用PureMVC,谨以一个登录的例子,说明如何使用PureMVC构建工程,工程结构图如下:
因为所有的 Mediator、Proxy、Command、Event 的名称都被我定义在system包下的NameSpace.as中,所以先看给出此as的代码:
package system
{public class NameSpace
{
public static const LoginProxyName:String=”LoginProxy”;
public static const LoginSuccess:String=”loginSuccess”;
public static const LoginFailed:String=”loginFailed”;
public static const LoginEvent:String=”loginEvent”;
public static const LoginMediatorName:String=”loginMediator”;
public static const ApplicationLogin:String=”login”;
public static const ApplicationMediatorName:String=”appliactionMediator”;
public static const FacadeStart:String=”start”;
}
}
因为数据来自Model层,我们用Proxy进行管理,所以我们先来设计这一模块,定义LoginVO这样一个简单的数据结构,用于存储登录的数据:用户名和密码。代码如下:
package model.vo
{
public class LoginVO
{
public var username:String;
public var password:String;
}
}
接着建立LoginProxy,需要继承Proxy实现IProxy:
package model
{
import model.vo.LoginVO;
import org.puremvc.as3.interfaces.IProxy;
import org.puremvc.as3.patterns.proxy.Proxy;
import system.NameSpace;public class LoginProxy extends Proxy implements IProxy
{
public function LoginProxy()
{
super(NameSpace.LoginProxyName);
}public function CheckLogin(vo:LoginVO):void
{
if (vo.username == “test” && vo.password == “test”)
{
sendNotification(NameSpace.LoginSuccess, vo);
}
else
{
sendNotification(NameSpace.LoginFailed);
}
}
}
}
每一个Proxy都需要有自己的名称,为了便于统一的管理,我把所有的Name都定义在NameSpace中,这样做的好处是有利于协作开发,同时也有助于程式的调试。从代码中可以看到,整个Model与外界没什么联系,提供了一个CheckLogin()方法,根据判断的结果发送通知。至于这样的通知发送出去谁来处理,怎么处理,就不是Proxy关心的事了。由此可知,Proxy的耦合度相当低!(感觉PureMVC这个组织里,Facade是老大,管着手下三个小弟:Proxy、Mediator、Command,这三个家伙都是各干各的,从不互相帮助,各人自扫门前雪,真是selfish)
任何一个应用都有和用户交互的界面,将这些界面统一起来进行管理,就是PureMVC的View层。在View层内,实现界面的管理委托给了Mediator,Mediator负责管理应用界面的数据更新和提交数据。当用户界面发生数据更新或用户操作时,界面通过事件通知管理它的Mediator,然后Mediator会根据情况发送通知给系统。先建议一个登录的界面:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Panel xmlns:mx=”http://www.adobe.com/2006/mxml”
fontSize=”12″
layout=”vertical”
horizontalAlign=”center”
title=”用户登录”
width=”314″>
<mx:Script>
<![CDATA[
import system.NameSpace;
]]>
</mx:Script>
<mx:Form width=”100%”
height=”100%”>
<mx:FormHeading label=”敬请登录”/>
<mx:FormItem label=”登录名称”>
<mx:TextInput id=”loginName”/>
</mx:FormItem>
<mx:FormItem label=”登录密码”>
<mx:TextInput id=”loginPassword”/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label=”确定”
id=”loginBtn”
click=”dispatchEvent(new Event(NameSpace.LoginEvent))”/>
</mx:FormItem>
</mx:Form>
<mx:Label id=”labStatus”/>
</mx:Panel>
基于这个界面,定义两个Mediator:一个是LoginMediator,负责管理登录对话框和登录的操作;另一个是ApplicationMediator,用来负责管理登录成功后的界面。先看LoginMediator:
package view
{
import flash.events.Event;import model.vo.LoginVO;
import mx.managers.PopUpManager;
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.mediator.Mediator;import system.NameSpace;
public class LoginMediator extends Mediator implements IMediator
{
//获取应用实例
private var loginPanel:LoginForm;
private var loginApplication:PureLoginMVC;public function LoginMediator(app:Object)
{
super(NameSpace.LoginMediatorName, app);
loginApplication=app as PureLoginMVC;
loginPanel=new LoginForm();
loginPanel.addEventListener(NameSpace.LoginEvent, onLogin);
PopUpManager.addPopUp(loginPanel, loginApplication);
PopUpManager.centerPopUp(loginPanel);
}//监听通知
override public function listNotificationInterests():Array
{
var arr:Array=new Array();
arr.push(NameSpace.LoginSuccess);
arr.push(NameSpace.LoginFailed);
return arr;
}//响应通知
override public function handleNotification(notification:INotification):void
{
switch (notification.getName())
{
case NameSpace.LoginSuccess:
setLoginSuc();
break;
case NameSpace.LoginFailed:
setLoginFailed();
break;
default:
break;
}
}//登录成功,移除登录窗口
private function setLoginSuc():void
{
PopUpManager.removePopUp(loginPanel);
}//登录失败,提示
private function setLoginFailed():void
{
loginPanel.labStatus.text=”用户名密码有误,请重试”;
loginPanel.loginName.setFocus();
}private function onLogin(evt:Event):void
{
if (loginPanel.loginName.text != “” && loginPanel.loginPassword.text != “”)
{
var loginVO:LoginVO=new LoginVO();
loginVO.username=loginPanel.loginName.text;
loginVO.password=loginPanel.loginPassword.text;
sendNotification(NameSpace.ApplicationLogin, loginVO);
}
else
{
loginPanel.labStatus.text=”请输入用户名和密码”;
}
}}
}
同样,LoginMediator 的名称来自于 NameSpace.as ,继承Mediator实现IMediator,LoginMediator 注册监听了两个事件:登录成功和失败,并做了对应的响应处理。其中onLogin()方法在收集了登录信息后,发出通知。另外还有一个ApplicationMediator:
package view
{
import model.vo.LoginVO;import mx.controls.Label;
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.mediator.Mediator;import system.NameSpace;
public class ApplicationMediator extends Mediator implements IMediator
{
private var loginApplication:PureLoginMVC;//构造器,获取application实例
public function ApplicationMediator(app:Object)
{
super(NameSpace.ApplicationMediatorName, app);
loginApplication=app as PureLoginMVC;
}//监听通知
override public function listNotificationInterests():Array
{
return [NameSpace.LoginSuccess];
}//响应通知
override public function handleNotification(notification:INotification):void
{
switch (notification.getName())
{
case NameSpace.LoginSuccess:
setLoginSuc(notification.getBody() as LoginVO);
break;
default:
break;
}
}private function setLoginSuc(loginVO:LoginVO):void
{
var label:Label=new Label();
label.text=”欢迎光临!” + loginVO.username;
loginApplication.addChild(label);
}}
}
这个mediator只监听了登录成功的通知,并响应更新主应用上的数据。
Controller和Command看起来像一条纽带,联系这Mediator和Proxy.它处理Mediator发送的通知并调用Proxy中的public 方法来处理. Command需要继承SimpleCommand或MocroCommand并实现ICommand.分析系统,需要在Command中注册Proxy和Mediator,以及一个处理Login的。这里的设计思路为:ModelCommand(用于注册Proxy)、ViewCommand(注册Mediator)、ApplicationCommand(用于系统启动时,集成ModelCommand和ViewCommand)、LoginCommand(用于接收登录通知并调用Proxy实现登录)。先看ModelCommand:
package Controller
{
import model.LoginProxy;import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;public class ModelCommand extends SimpleCommand implements ICommand
{
public function ModelCommand()
{
super();
}override public function execute(notification:INotification):void
{
facade.registerProxy(new LoginProxy());
}}
}
接着写ViewCommand:
package Controller
{
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;import view.ApplicationMediator;
import view.LoginMediator;public class ViewCommand extends SimpleCommand implements ICommand
{
public function ViewCommand()
{
super();
}//注册Mediator
override public function execute(notification:INotification):void
{
var app:PureLoginMVC=notification.getBody() as PureLoginMVC;
facade.registerMediator(new ApplicationMediator(app));
facade.registerMediator(new LoginMediator(app));
}}
}
在ApplicationCommand中集成注册上面两个Command:
package Controller
{
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.patterns.command.MacroCommand;public class ApplicationCommand extends MacroCommand implements ICommand
{
//构造器,可写可不写
public function ApplicationCommand()
{
super();
}//写法一
override protected function initializeMacroCommand():void
{
addSubCommand(ModelCommand);
addSubCommand(ViewCommand);
}}
}
处理登录通知的LoginCommand:
package Controller
{
import model.LoginProxy;
import model.vo.LoginVO;import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;import system.NameSpace;
public class LoginCommand extends SimpleCommand implements ICommand
{
public function LoginCommand()
{
super();
}override public function execute(notification:INotification):void
{
var loginVO:LoginVO=notification.getBody() as LoginVO;
//var loginProxy:LoginProxy = new LoginProxy();
//从facade中获取proxy
var loginProxy:LoginProxy=facade.retrieveProxy(NameSpace.LoginProxyName) as LoginProxy;
loginProxy.CheckLogin(loginVO);
}}
}
完成了这些之后,就到了 PureMVC 的核心:Facade,通过它,Mediator,Proxy,Command才能很好的结合在一起。这里将它命名为MyFacade,代码如下:
package MyApp
{
import MyApp.Controller.GetUrlListCommand;
import MyApp.Controller.StartUpCommand;
import org.puremvc.as3.interfaces.IFacade;
import org.puremvc.as3.patterns.facade.Facade;
public class MyAppFacade extends Facade implements IFacade
{
public static const APP_STARTUP:String = 'app_startup';
public static const APP_STARTUP_OVER:String = 'app_startup_over';
public function MyAppFacade()
{
super();
}
public static function getInstance():MyAppFacade {
if (instance == null) {
instance = new MyAppFacade();
}
return instance as MyAppFacade;
}
override protected function initializeController():void {
super.initializeController();
//注册一些command
registerCommand(APP_STARTUP, StartUpCommand);
registerCommand(APP_STARTUP_OVER, GetUrlListCommand);
}
public function startup(app:Object):void {
sendNotification(APP_STARTUP, app);
}
}
}
最后,在主应用中单例调用MyFacade的实例:
<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application fontSize=”12″
xmlns:mx=”http://www.adobe.com/2006/mxml”
creationComplete=”init()”
layout=”absolute”>
<mx:Script>
<![CDATA[
import system.MyFacade;
import org.puremvc.as3.patterns.facade.Facade;public function init():void
{
var myFacade:MyFacade=MyFacade.getInstance();
myFacade.startup(this);
}
]]>
</mx:Script>
</mx:Application>
到此为止,一个PureMVC构建的登录例子就完成了,呵呵,希望能达到一看就懂的效果~
源码下载:PureMVCLogin.rar (523)