网络上目前流行的flex框架不少,包括地位资深出身名门的cariagorm ,当前走红的PureMVC,轻盈小巧的Model-Glue,Foundry ,ARP等。权衡了下利弊,选择了PureMVC。 主要因为PureMVC扩展性顶好,并且它与语言无关。
由于是hello word,个人懒得写例子,所以采用的是网上某位同僚的例子,略加改进,如图,点击上一张/下一张切换图片。例子很简单,没必要用框架。但主要为了学习框架。
目录的架构介绍如下:
整个框架运作可以看作订单流程如图:
根据AVM的执行顺序,来介绍整个框架的运转:
首先运行HelloPureMVC.xml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
creationComplete="initApp()"
xmlns:component="component.*"
fontSize="12">
<mx:Script>
<![CDATA[
import MyApp.MyAppFacade;
public function initApp():void{
var facade:MyAppFacade = MyAppFacade.getInstance();
facade.startup( this );
}
]]>
</mx:Script>
<mx:Box id="mainContainer" width="202" height="250">
<component:Mydisplay id="display" width="200" height="200"/>
<component:MyControlBar id="controlBar" x="0" y="200" height="50" width="200" />
</mx:Box>
</mx:Application>
这个界面很简单,在一个BOX组件中添加2个自制组件,这两个自制组件Mydisplay和MyControlBar,在启动该应用时,加载initApp方法,获得MyAppFacade实例,启动pureMVC框架。下面便是2个组件的代码:
Mydisplay.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label id="nameLabel"/>
<mx:Image id="image" y="30"/>
</mx:VBox>
MyControlBar.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:ControlBar xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Button label="上一张" fontSize="12" id="btnPrev"/>
<mx:Button label="下一张" fontSize="12" id="btnNext"/>
</mx:ControlBar>
MyAppFacade.as就是流图中的接单者,总裁。该角色继承了Facade ,实现了IFacade,可以说是有权有势。
package myApp
{
import myApp.controller.GetUrlListCommand;
import myApp.controller.StartupCommand;
import org.puremvc.as3.interfaces.IFacade;
import org.puremvc.as3.patterns.facade.Facade;
/**
* 该类作为框架的掌控者,它所做的事情主要包括:
* 1.提供获取自身实例的getInstance()静态方法
* 2.initializeController()初始化Controller控制器
* 建立Notification与Command映射
* 在该例子中建立了程序启动,Puremvc启动结束的command映射
* 3.startup(obt:Object)该方法提供给界面调用,启动pureMVC
* 4.运行顺序为:initializeController()->getInstance()->startup(app:Object)
* */
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();
trace("getInstance()");
return instance as MyAppFacade;
}
override protected function initializeController():void{
trace("initializeController()");
super.initializeController();
//register some Commands
registerCommand(APP_STARTUP,StartupCommand);
registerCommand(APP_STARTUP_OVER,GetUrlListCommand);
}
public function startup(app:Object):void{
trace("startup(app:Object)");
sendNotification(APP_STARTUP,app);
}
}
}
它任命了StartupCommand为总经理,StartupCommand继承了MacroCommand ,能够对下层经理发命令。这里下层的经理包括ModelPrepCommand和ViewPrepCommand
package myApp.controller{
import org.puremvc.as3.patterns.command.MacroCommand;
/**
*
* 该类继承了MacroCommand将会在单例modelController和viewsController启动前调用
* 当该类加载时执行初始化方法,initializeMacroCommand(),该方法中初始化2个控制器,初
* 始化的顺序按照代码的书写顺序.
*
*
* **/
public class StartupCommand extends MacroCommand {
// 程序开始时执行的 MacroCommand.
public function StartupCommand() {
return;
}
//添加子Command 初始化 MacroCommand.
override protected function initializeMacroCommand():void {
//以下两个命令按先进先出顺序执行;
trace("initializeMacroCommand()");
addSubCommand(ModelPrepCommand);
addSubCommand(ViewPrepCommand);
return;
}
}
}
ModelPrepCommand是管理model层的经理,也就是生产者经理。所有的材料,用品都要由这个部门负责。但ModelPrepCommand管理的是主管ImageUrlListProxy。
package myApp.controller{
import myapp.model.*;
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;
import myApp.model.ImageUrlListProxy;
/**
*
* ModelPrepCommand作为系统的model控制器,管理了所有的model对象,model在整个pureMVC中起到了
* 与数据交互的作用.这里需要注册一个proxy.该proxy的注册方式:
* facede获取proxy对象参数传递给proxy类对象,该类对象会将该proxy对象放置数组中,在系统调用
* retrieveProxy的时候,将获得该proxy实例.
*
*
* **/
public class ModelPrepCommand extends SimpleCommand implements ICommand {
public function ModelPrepCommand() {
return;
}
//注册代理(proxy)
public override function execute(sender:INotification):void {
trace("ModelPrepCommand");
facade.registerProxy( new ImageUrlListProxy(ImageUrlListProxy.NAME) );
}
}
}
主管ImageUrlListProxy就叫A准备生产A货物,B准备调用B材料。这里是在xml中,调用数据。但是还没收到上级的命令,他们没有调用数据的。XML数据如下:
**************************************
<persons>
<person name="卡莫" source="pic/km.jpg"/>
<person name="李时珍" source="pic/lsz.jpg"/>
<person name="姚明" source="pic/ym.jpg"/>
<person name="费德勒" source="pic/fdl.jpg"/>
<person name="伍兹" source="pic/wz.jpg"/>
<person name="科比" source="pic/kb.jpg"/>
</persons>
**************************************
package myApp.model
{
import myApp.model.vo.ImageUrlVO;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
import org.puremvc.as3.interfaces.IProxy;
import org.puremvc.as3.patterns.proxy.Proxy;
/**
*
* 该类用作获得数据,还提供了一个loadUrlList方法.
*
* **/
public class ImageUrlListProxy extends Proxy implements IProxy
{
public static const NAME:String = "ImageUrlListProxy";
private var hs:HTTPService;
//定义一些Notification字符常量
public static const URL_LOAD_COMPLETE:String = "url_load_complete";
public function ImageUrlListProxy(proxyName:String=null, data:Object=null)
{
trace("ImageUrlListProxy(proxyName:String=null, data:Object=null)");
super(proxyName,data);
hs = new HTTPService();
hs.addEventListener(ResultEvent.RESULT,onResult);
hs.addEventListener(FaultEvent.FAULT,fault);
}
public function loadUrlList():void{
hs.url = "xml/person.xml";
hs.resultFormat ="e4x";
hs.send();
}
public function fault(event:FaultEvent):void{
trace(event.message);
}
public function onResult(event:ResultEvent):void{
data = new Array();
var personList:XML = event.result as XML;
for each(var p:XML in personList.person){
var personName:String = p.@name;
var personPic:String = p.@source;
data.push(new ImageUrlVO(personPic,personName));
}
if(data==null)Alert.show("数据为空");
sendNotification( URL_LOAD_COMPLETE,data );
}
}
}
*********调用的材料*********
package myApp.model.vo
{
public class ImageUrlVO
{
public var url:String;
public var name:String;
public function ImageUrlVO(url:String,name:String){
this.url = url;
this.name = name;
}
}
}
*********调用的材料*********
下层经理ViewPrepCommand在ModelPrepCommand做完后,立马开工,招来发货主管ImageMediator,ControlBtnsMediator把订货单列出
《var app:HelloPureMVC = notification.getBody() as HelloPureMVC;》
HelloPureMVC需要这些东西,你们开始准备吧。(生产者ModelPrepCommand不需要知道货是谁要的,只管生产)
package myApp.controller{
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;
import myApp.view.ImageMediator;
import myApp.MyAppFacade;
import myApp.view.ControlBtnsMediator;
public class ViewPrepCommand extends SimpleCommand implements ICommand {
public function ViewPrepCommand() {
return;
}
// 创建 Mediator, 并把它们注册到View;
public override function execute(notification:INotification):void {
//得到载体
var app:HelloPureMVC = notification.getBody() as HelloPureMVC;
trace("ViewPrepCommand");
//注册ImageMediator和ControlBtnsMediator
facade.registerMediator( new ImageMediator(app.display) );
facade.registerMediator( new ControlBtnsMediator(app.controlBar) );
//通知已经初始化完毕
sendNotification(MyAppFacade.APP_STARTUP_OVER,app);
}
}
}
ImageMediator主管首当其冲,弄清自己的任务艰巨(显示图片,显示名字,在点击按钮后作出反应),分清主次先super(NAME, viewComponent);再让专门请了个人去监听广播listNotificationInterests,得到信号组(可自己看框架源码)后,handleNotification,组成专案组,完成各自的任务。
package myApp.view
{
import myApp.model.ImageUrlListProxy;
import myApp.model.vo.ImageUrlVO;
import component.MyControlBar;
import mx.controls.Alert;
import mx.controls.Button;
import mx.controls.Image;
import mx.controls.Label;
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.mediator.Mediator;
public class ImageMediator extends Mediator implements IMediator
{
public static const NAME:String = "ImageMediator";
private var arrayOfImage:Array=null;
private var currentIndex:int=-1;
public function ImageMediator(viewComponent:Object)
{
trace("ImageMediator");
super(NAME, viewComponent);
}
override public function listNotificationInterests():Array{
//列出感兴趣的Notification
trace("listNotificationInterests()");
return [
ImageUrlListProxy.URL_LOAD_COMPLETE,
ControlBtnsMediator.NEXT_IMAGE,
ControlBtnsMediator.PREV_IMAGE
];
}
override public function handleNotification(notification:INotification):void{
trace("handleNotification(notification:INotification)");
switch(notification.getName()){
case ImageUrlListProxy.URL_LOAD_COMPLETE:
arrayOfImage = notification.getBody() as Array;
if(arrayOfImage){
(viewComponent.nameLabel as Label).text = (arrayOfImage[0] as ImageUrlVO).name;
(viewComponent.image as Image).source = (arrayOfImage[0] as ImageUrlVO).url;
currentIndex = 0;
}else{
Alert.show("没有得到图片链接","错误");
}
break;
case ControlBtnsMediator.NEXT_IMAGE:
if(currentIndex==-1)break;
if(currentIndex >= arrayOfImage.length-1 ){Alert.show("目前是最后一张图片","警告");}
else{
(viewComponent.nameLabel as Label).text = (arrayOfImage[currentIndex+1] as ImageUrlVO).name;
(viewComponent.image as Image).source = (arrayOfImage[currentIndex+1] as ImageUrlVO).url;
currentIndex++;
}
break;
case ControlBtnsMediator.PREV_IMAGE:
if(currentIndex==-1)break;
if(currentIndex <=0 ){Alert.show("目前是第一张图片","警告");}
else{
(viewComponent.nameLabel as Label).text = (arrayOfImage[currentIndex+-1] as ImageUrlVO).name;
(viewComponent.image as Image).source = (arrayOfImage[currentIndex-1] as ImageUrlVO).url;
currentIndex--;
}
break;
default:break;
}
}
}
}
ControlBtnsMediator主管比较闲,主要负责看看是不是有人按了按钮就行。如果有人按了按钮,就发广播通知各单位:按了按钮,按了那个按钮。
package myApp.view
{
import flash.events.MouseEvent;
import mx.controls.Button;
import org.puremvc.as3.interfaces.IMediator;
import org.puremvc.as3.patterns.mediator.Mediator;
public class ControlBtnsMediator extends Mediator implements IMediator
{
public static const NAME:String = "ControlBtnsMediator";
public static const NEXT_IMAGE:String = "next_image";
public static const PREV_IMAGE:String = "prev_image";
public function ControlBtnsMediator(viewComponent:Object)
{
super(NAME, viewComponent);
trace("ControlBtnsMediator");
(viewComponent.btnPrev as Button).addEventListener(MouseEvent.CLICK,onClickPrev);
(viewComponent.btnNext as Button).addEventListener(MouseEvent.CLICK,onClickNext);
}
private function onClickPrev(e:MouseEvent):void{
sendNotification(PREV_IMAGE);
}
private function onClickNext(e:MouseEvent):void{
sendNotification(NEXT_IMAGE);
}
}
}
ViewPrepCommand经理在主管工作都准备好了后,就广播
sendNotification(MyAppFacade.APP_STARTUP_OVER,app); ,
总裁的秘书1号监听
registerCommand(APP_STARTUP_OVER,GetUrlListCommand);
去把货物提了出来
package myApp.controller
{
import myApp.model.ImageUrlListProxy;
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;
public class GetUrlListCommand extends SimpleCommand implements ICommand
{
public function GetUrlListCommand()
{
super();
}
override public function execute(notification:INotification):void
{
//得到图片链接
trace("GetUrlListCommand");
(facade.retrieveProxy( ImageUrlListProxy.NAME ) as ImageUrlListProxy).loadUrlList();
}
}
}
秘书在调完货后,发送广播,货物准备好了sendNotification( URL_LOAD_COMPLETE,data );,ImageMediator主管一直在监听,听到URL_LOAD_COMPLETE消息后,立马handleNotification,看看是什么消息,然后就执行里面对应的方法。采用的是switch case ,有效执行命令。
下面附有整个demo的例子以及pureMVC的源码.供大家下载.