|
做flex做久做大了,使用一個框架便是自然而然的事情。這樣程序才會更健壯,更易于擴展,更易于維護。pureMVC足夠簡單,核心也只有十來個類,是一個輕量級的Flex框架,只一天的時間,就可以學通,沒有理由不用它的。
麻雀雖小,五臟俱全,pureMVC,直譯過來就是“純MVC”,是一個MVC框架。官方的中文文檔有44頁,放在附件中,可以下載了看。推薦一個入門的文章給大家。(http:///showtopic-11011.html ),里面有足夠全面的介紹。這里我想利用一個更加簡單的圖片展示的例子來展示pureMVC的使用細節(jié)。先看效果:
介紹一下這個應用。程序一開始便請求展示的圖片信息(包括圖片的鏈接以及名稱),得到信息后便可以通過兩個按鈕進行逐張的瀏覽。這個例子太簡單了,以致根本沒有必要去用pureMVC,這里我只是想借用它來介紹pureMVC如何使用的。
如果將上面的例子假設為做菜,哈哈,就會更有意思了。兩個 Button ,一個 Image 與 Label 便是鍋碗瓢盆,而圖片的信息便是原料,而怎么樣來炒,便要看菜譜了。pureMVC 的設計者估計也是做菜的高手。這些對他們來說就是 Model (原料), View (鍋碗瓢盆), Controller (菜譜),三個都是單例模式。同時他們還設計出一個廚師,叫 Facade ,由它來調度上面三個,也是單例的。
一切從 Facade 開始,它實列化 Model , View , Controller 。MVC 也找了一些幫手, Model 找到的是 Proxy 們,代理?好像翻譯得不對。不管,以后的數據就靠它了。View 找的是 Mediator,它們負責UI,Controller 找的是 Command,不過 Command 性格比較怪,做完一次任務就不干了,也就是短生命同期的。每次用它 pureMVC 都會重新創(chuàng)建。所以只能用它來做業(yè)務邏輯,而不要將長期的數據放在里面。
pureMVC 消息采用的觀察者模式,每次做完一件事情,就可以向外發(fā)出一個 Notification (不是 Flex 里的 Event 喲),就像向外宣布“事情做完了”,具體誰關心就管不著了。這里 Proxy 有點特別,它們只會向外發(fā)出 Notification ,但從不接收,只關心自己的數據模型。這很有意義,想想人家叫 “純MVC” 嘛。
好了,開始做這個例子。剛開始學東西的時候總會發(fā)現,文檔都看懂了,東西好像都會了。真要用它做東西,卻不知道怎么下手。所以還要再好好分析下程序,看看怎么樣下手。
首先界面上就四個控件,兩個Button ,一個 Image 和 一個Label ,從功能上可以分為兩類,兩個 Button 是用來作控制的, Image 與 Label 用來顯示圖片及圖片名稱。和 UI 對應的是 Mediator ,所以要定義兩個 Mediator 類。如果程序變大了,也可以這樣來劃分,千萬不要為每個按鈕作一個 Mediator ,也不要整個 Application 才一個 Mediator,最好按功能來劃分。
然后再來看 Model ,本例中的數據只有一項,便是要顯示的圖片資料。所以只要求定義一個 Proxy 用來數據交互就夠了。flex 得到數據的方式有許多種,如HttpService ,RemoteObject ,XMLSocket等,但不管什么,總之都是從其他地方得到有用的信息,然后將它變成自己自己的程序能夠理解的形式。當然解析數據,大多是業(yè)務邏輯( Controller )的工作了。
再看Controller這邊,Controller 涉及到業(yè)務 ,本例中業(yè)務有程序啟動(StartUp),還有個就是得到圖片信息。還有嗎,好像沒有了。兩個Command就可以應付了。
好了,可以動手編碼了。
定義兩個Mediator (ImageMediator 與 ControlBtnsMediator,繼承Mediator類,實現IMediator接口), 兩個Command ( StartUpCommand 與 GetUrlListCommand,繼承SimpleCommand類,實現ICommand) 以及一個Proxy (ImageUrlListProxy ,繼承Proxy,實現IProxy接口) 一個圖片信息類(ImageUrlVO),用來存放單張圖片信息。 一個Facade (MyAppFacade 繼承Facade,實現IFacade接口)
程序的包結構:
同時思考需要的 Notification ,它是將整個框架聯系起來的關鍵。 1.程序開始便要啟動 StrartUpCommand,所以StrartUpCommand 要關注 "app_startup" 2.StrartUpCommand主要完成Proxy與Mediator的注冊,完成后便可以啟動GetUrlListCommand,所以GetUrlListCommand應關注"app_startup_over" 3.GetUrlListCommand 通過 ImageUrlListProxy去獲取圖片信息,前面提到 ImageUrlListProxy是不能接收Notification,所以GetUrlListCommand要直接調用ImageUrlListProxy的public成員函數loadUrlList()去獲取圖片信息 4.ImageUrlListProxy 得到圖片鏈接以后,便可以對外宣布“圖片信息已經得到了”,即對外Send一個"url_load_complete"的Notification,關注這一Notification的自然是ImageMediator,它直接將圖片信息保存起來,并顯示第一張圖片內容 5.ControlBtnsMediator不需要關注任何Notification,不過點擊兩個按鈕時會向外Send Notification ("next_image" 與 "prev_image"),,通知顯示下一張或上一張圖片。關注這兩個Notification的自然是ImageMediator了。
好了,流程都介紹完了,來看代碼。
先定義類 ImageUrlVO 的代碼如下:
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;
}
}
}
接下來從程序的執(zhí)行步驟依次看各個類的代碼。
主界面 HelloPureMVC.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="200" height="200" creationComplete="initApp()">
<mx:Script>
<![CDATA[
import MyApp.MyAppFacade;
public function initApp():void{
var facade:MyAppFacade = MyAppFacade.getInstance();
facade.startup( this );
}
]]>
</mx:Script>
<mx:Canvas id="mainContainer" width="100%" height="100%">
<mx:Label id="nameLabel" x="87.5" y="0"/>
<mx:Image id="image" x="30" y="20" width="140" height="140"/>
<mx:Button x="10" y="168" label="上一張" id="btnPrev"/>
<mx:Button x="125" y="168" label="下一張" id="btnNext"/>
</mx:Canvas>
</mx:Application>
主界面現在只關注布局就夠了。同時還要注意到里面的initApp()函數,它首先得到Facade實例,再調用其 startup() 函數啟動整個PureMVC框架。 跟進去再讓看 MyAppFacade 的實現。
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();
//register some Commands
registerCommand(APP_STARTUP,StartUpCommand);
registerCommand(APP_STARTUP_OVER,GetUrlListCommand);
}
public function startup(app:Object):void{
sendNotification(APP_STARTUP,app);
}
}
}
可見Facade做的事情很簡單, initializeController() 是用來初始化Controller的,這個函數是建立各個Notification與Command映射的地方,有了上面的流程分析,
registerCommand(APP_STARTUP,StartUpCommand); registerCommand(APP_STARTUP_OVER,GetUrlListCommand); 這兩行這很容易了。startup()函數,終于輪到它了。它只做了一件事情,就是向外派發(fā)一個APP_STARTUP的Notification,關注它的是前面已經建立映射的StartUpCommand,pureMVC會實例化一個StartUpCommand的實例,并將app作為參數,調用其execute函數。 tip:通常用一個字符串來標識一個Notification,不過建議用字符常量。減少犯錯的可能。
再來看StartUpCommand的代碼:
package MyApp.Controller
{
import MyApp.Model.ImageUrlListProxy;
import MyApp.MyAppFacade;
import MyApp.View.ControlBtnsMediator;
import MyApp.View.ImageMediator;
import org.puremvc.as3.interfaces.ICommand;
import org.puremvc.as3.interfaces.INotification;
import org.puremvc.as3.patterns.command.SimpleCommand;
public class StartUpCommand extends SimpleCommand implements ICommand
{
public function StartUpCommand()
{
super();
}
override public function execute(notification:INotification):void
{
var app:HelloPureMVC = notification.getBody() as HelloPureMVC;
//注冊代理(proxy)
facade.registerProxy( new ImageUrlListProxy( ImageUrlListProxy.NAME ) );
//注冊中介器
facade.registerMediator( new ImageMediator(
ImageMediator.NAME,
{
image:app.image,
nameLabel:app.nameLabel
}
) );
facade.registerMediator( new ControlBtnsMediator(
ControlBtnsMediator.NAME ,
{
btnNext:app.btnNext,
btnPrev:app.btnPrev
}
) );
//通知已經初始化完畢
sendNotification(MyAppFacade.APP_STARTUP_OVER,app);
}
}
}
只有一個execute()函數,它的任務便是注冊前面提到的兩個Mediator和一個Proxy,用到的是registerProxy()與registerMediator()兩個函數,完成注冊后便可以對外Send MyAppFacade.APP_STARTUP_OVER 了。關注這一Notificator的便是前面已經建立映射的 GetUrlListCommand 。同樣一個 GetUrlListCommand 會被實例化,再調用其execute()函數。
tip:Proxy類的構造函數需要一個proxyName:String作為其唯一標識,可以通過這一字符串得到該Proxy的引用,這里也建議使用字符常量
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
{
//得到圖片鏈接
(facade.retrieveProxy( ImageUrlListProxy.NAME ) as ImageUrlListProxy).loadUrlList();
}
}
}
好簡單,呵呵,得到 ImageUrlListProxy 的實例,調用其loadUrlList()函數就可以了。前面提到Proxy不會去接收任何Notification,所以只能通過調用其成員函數的形式來使用它。 看看ImageUrlListProxy的代碼:
package MyApp.Model
{
import MyApp.Model.VO.ImageUrlVO;
import org.puremvc.as3.interfaces.IProxy;
import org.puremvc.as3.patterns.proxy.Proxy;
public class ImageUrlListProxy extends Proxy implements IProxy
{
public static const NAME:String = "ImageUrlListProxy";
//定義一些Notification字符常量
public static const URL_LOAD_COMPLETE:String = "url_load_complete";
public function ImageUrlListProxy(proxyName:String=null, data:Object=null)
{
super(proxyName,data);
}
public function loadUrlList():void{
data = new Array();
//push六張圖片的Url
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic1.jpg","卡莫"));
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic2.jpg","李時珍"));
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic3.jpg","姚明"));
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic4.jpg","費得了"));
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic5.jpg","伍茲"));
data.push(new ImageUrlVO("http://www./r/io/ioryioryzhan/pic6.jpg","不認得"));
//通知image Url已經全部得到了
if(data==null)trace("data is null");
sendNotification( URL_LOAD_COMPLETE ,data );
}
}
}
loadUrlList()函數去得到圖片信息,由于沒有后臺,所以只能用這種直接寫硬編碼的方式了, Proxy 有一個data成員,是個Object,用來盛放接收到的數據。得到數據后便可以Send一個Notification (URL_LOAD_COMPLETE)了。接下來看關注這個Notification的ImageMediator。
package MyApp.View
{
import mx.controls.Alert;
import mx.controls.Image;
import mx.controls.Label;
import MyApp.Model.ImageUrlListProxy;
import MyApp.Model.VO.ImageUrlVO;
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(mediatorName:String=null, viewComponent:Object=null)
{
super(mediatorName, viewComponent);
}
override public function listNotificationInterests():Array{
//列出感興趣的Notification
return [
ImageUrlListProxy.URL_LOAD_COMPLETE,
ControlBtnsMediator.NEXT_IMAGE,
ControlBtnsMediator.PREV_IMAGE
];
}
override public function handleNotification(notification:INotification):void{
switch(notification.getName()){
case ImageUrlListProxy.URL_LOAD_COMPLETE:
arrayOfImage = notification.getBody() as Array;
if(arrayOfImage){
trace(arrayOfImage.length);
trace((viewComponent.nameLabel as Label).text);
(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{
trace((viewComponent.nameLabel as Label));
(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;
}
}
}
}
ImageMediator除了關注ImageUrlListProxy.URL_LOAD_COMPLETE外,還要關注ControlBtnsMediator.NEXT_IMAGE以及ControlBtnsMediator.PREV_IMAGE,即為示下一張或上一張圖片。
具體怎么將Mediator與其關注的Notification關聯起來呢,listNotificationInterests(),就是它了。它要求返回一個字符數組,在注冊這個Mediator時,該函數就會被調用,之后,當一個Notification被發(fā)送時,如果該Notification的字符串存在于這個字符數組時,這個Mediator就能接收到。
處理Notification是在handleNotification()函數內進行的,通過switch/case的方式,對不同的Notification進行不同的處理。會MFC的筒子們一定會覺得好熟悉啊,在 MFC 里,窗口函數也是這樣來處理消息的。
具體代碼就不分析了,很簡單的。
最后就只有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(mediatorName:String=null, viewComponent:Object=null)
{
super(mediatorName, viewComponent);
(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);
}
}
}
注冊監(jiān)聽,響應時發(fā)送相應的Notification。 好了,都介紹完了,點擊運行吧。 附件中有一個pureMVC的中文文檔,以及Project的源文件,pureMVC的代碼Project的源文件中。 |
|
|
來自: 昵稱1974760 > 《actionscript》