PureMvc設計模式在AS中的應用例子

PureMVC實現的經典MVC元設計模式中,這三部分由三個單例模式類管理,分別是ModelViewController。三者合稱爲核心層或核心角色。各層之間能以一種鬆耦合的方式通信,並且與平臺無關。PureMVC的目標之一就是保持平臺無關性,不管你使用什麼技術什麼UI組件什麼數據結構都能應用PureMVC框架。它已經被移植到其他的一些平臺像C#SilverlightJ2ME.在我以前的文中已經說過mvc是三層結構,puremvc同樣由三層構成:
1.Model保存對Proxy對象的引用,Proxy負責操作數據模型;

2.View保存對Mediator對象的引用 。由Mediator對象來操作具體的視圖組件,包括:添加事件監聽器 ,發送或接收Notification ,直接改變視圖組件的狀態;

3.Controller保存所有Command的映射。Command類是無狀態的,只在需要時才被創建。
 

以下是個小例子,功能是點擊tab按鈕時,切換界面。

首先是文檔類Main.as:

package    
{
  import flash.display.Sprite;
  import flash.events.Event;
    
  import KingClass.ApplicationFacade
  /**
    * ...
    * @author Never
    */
  public class Main extends Sprite    
  {
    //通過單例模式 獲取ApplicationFacade
    private var facade:ApplicationFacade = ApplicationFacade.getInstance();    
    public function Main():void    
    {
      if (stage) init();
      else addEventListener(Event.ADDED_TO_STAGE, init);
    }
    
    private function init(e:Event = null):void    
    {
      //啓動PureMVC,在應用程序中調用此方法,並傳遞應用程序本身的引用
      facade.startup(this);
      removeEventListener(Event.ADDED_TO_STAGE, init);
      // entry point
    }
    
  }
    
}
 
在文檔類中我們調用了一個ApplicationFacade的單例模式類。ApplicationFacade繼承Façade,Façade類應用單例模式,它負責初始化核心層(ModelViewController),並能訪問它們的Public方法.這樣,在實際的應用中,你只需繼承Façade類創建一個具體的Façade類就可以實現整個MVC模式,並不需要在代碼中導入編寫ModelViewController類。ApplicationFacade有個startup方法,負責啓動PureMVC,我們在文檔類中調用此方法,並傳遞應用程序本身的引用,有一個可選的“報體”,“報體”可以是任意ActionScript對象。在這裏是main。
ApplicationFacade.as:
package KingClass{
  import KingClass.Controller.StartupCommand;
    
  import org.puremvc.as3.patterns.facade.Facade;

  public class ApplicationFacade extends Facade {
    public static const STARTUP:String            = "startup";
    public static const CHANGETABLE:String         = "changeTable";

    //得到ApplicationFacade單例的工廠方法
    public static function getInstance():ApplicationFacade {
      if (instance == null)
        instance = new ApplicationFacade();
      return instance as ApplicationFacade;
    }

    /*啓動PureMVC,在應用程序中調用此方法,並傳遞應用程序本身的引用
    有一個可選的“報體”,“報體”可以是任意ActionScript對象。*/
    public function startup(app:Object):void {
      sendNotification(STARTUP, app);
    }

    //註冊Command,建立Command與Notification之間的映射
    override protected function initializeController():void {
      super.initializeController();
      registerCommand(STARTUP, StartupCommand);
    }
  }
}
 
   好了,下面我們來看看三層結構如何規劃,我們根據文檔類的順序,首先介紹CommandCommand對象是無狀態的;只有在需要的時候(Controller收到相應的Notification)纔會被創建,並且在被執行(調用execute方法)之後就會被刪除.Command要實現ICommand接口。在PureMVC中有兩個類實現了ICommand接口:SimpleCommandMacroCommandSimpleCommand只有一個execute方法,execute方法接受一個Inotification實例做爲參數。實際應用中,你只需要重寫這個方法就行了。MacroCommand在構造方法調用自身的initializeMacroCommand方法。實際應用中,你需重寫這個方法,調用addSubCommand添加子Command。你可以任意組合SimpleCommandMacroCommand成爲一個新的Command

 
StartupCommand.as 它繼承MacroCommand,啓動兩個繼承SimpleCommand的command。
package KingClass.Controller
{
  import KingClass.ApplicationFacade;

  import org.puremvc.as3.patterns.command.MacroCommand;

  public class StartupCommand extends MacroCommand    
  {
    override protected function initializeMacroCommand():void{
      this.addSubCommand(ModelPrepCommand);        
                        this.addSubCommand(ViewPrepCommand);        
                        /* 註冊添加、刪除用戶命令 */        
                        facade.registerCommand(ApplicationFacade.CHANGETABLE,ChangeComman);        
    }
  }
}
 
ModelPrepCommand.as 它註冊一個model
package KingClass.Controller    
{
  import org.puremvc.as3.patterns.command.SimpleCommand;
  import org.puremvc.as3.interfaces.INotification;    

  import KingClass.Model.ShowProxy;
  /**
    * ...
    * @author Never
    */
  public class ModelPrepCommand extends SimpleCommand
  {
    public function ModelPrepCommand() {    
      return;    
    }    

    override public function execute(notification:INotification):void        
                {        
                        /* 註冊Model */        
                        facade.registerProxy(new ShowProxy());        
                }    
  }
}
 
ViewPrepCommand.as(初始化界面)
package KingClass.Controller    
{
  import org.puremvc.as3.patterns.command.SimpleCommand;
  import org.puremvc.as3.interfaces.ICommand;    
  import org.puremvc.as3.interfaces.INotification;
    
  import KingClass.View.*;
    
  /**
    * ...
    * @author Never
    */
  public class ViewPrepCommand extends SimpleCommand
  {
    public function ViewPrepCommand() {    
      return;    
    }    
    
    override public function execute(notification:INotification):void        
                {    
      var obj:Main;    
      obj = notification.getBody() as Main;    
      facade.registerMediator(new ShowMediator(obj));
      facade.registerMediator(new TopMediator(obj));    
      return;    
    }
    
  }
}
 
接下來是: 
Mediator

Mediator保存了一個或多個View Component的引用,通過View Component自身提供的API管理它們.Mediator的主要職責是處理View Component派發的事件和系統其他部分發出來的Notification(通知)。因爲Mediator也會經常和Proxy交互,所以經常在Mediator的構造方法中取得Proxy實例的引用並保存在Mediator的屬性中,這樣避免頻繁的獲取Proxy實例。

通常一個Mediator只對應一個View Component,但卻可能需要管理多個UI控件

1.檢查事件類型或事件的自定義內容。

2.檢查或修改View Component的屬性(或調用提供的方法)。

3.檢查或修改Proxy對象公佈的屬性(或調用提供的方法)。

4.發送一個或多個Notification,通知別的MediatoraCommand作出響應(甚至有可能發送給自身)。

Mediator實例化時,PureMVC會調用MediatorlistNotificationInterests方法查詢其關心的 NotificationMediator則在listNotificationInterests方法中以數據形式返回這些Notification 名稱,例如下面的ShowMediator.asMediator對外不應該公佈操作View Component的函數。而是自己接收Notification做出響應來實現。
ShowMediator.as(爲可以切換的界面ShowCom.as的引用,他是根據傳遞的報體main添加組件到顯示列表中)
package KingClass.View    
{
  import flash.display.DisplayObject;
  import org.puremvc.as3.patterns.mediator.Mediator;
        import org.puremvc.as3.interfaces.IMediator;
  import org.puremvc.as3.interfaces.ICommand;
  import org.puremvc.as3.interfaces.INotification;
    
  import KingClass.Model.ShowProxy;
  import KingClass.View.Components.ShowCom;
  import KingClass.ApplicationFacade
  import KingClass.Model.Vo.IndexVo;
  /**
    * ...
    * @author Never
    */
  public class ShowMediator extends Mediator implements IMediator
  {
    public static const NAME:String = "ShowMediator";
    private var _showCom:ShowCom = new ShowCom();

    public function ShowMediator(viewComponent:DisplayObject = null)
                {
                        super(NAME, viewComponent);
        
      main.addChild(_showCom);    
    }
    
    
    private function get main():Main {    
      return viewComponent as Main;    
    }
    
    override public function listNotificationInterests():Array {
      return [
        ApplicationFacade.CHANGETABLE
      ];
    }
    
    override public function handleNotification(notification:INotification):void {
      switch(notification.getName()) {
        case ApplicationFacade.CHANGETABLE:    
          _showCom.Goto(int((facade.retrieveProxy(ShowProxy.NAME) as ShowProxy).newData.index));
        break;
      }
    }

    //end class
  }
}
 
 TopMediator.as(爲可以按鈕界面TopCom.as的引用,而組件showCom發生變化時,它監聽自定義的時間UIEvent)
package KingClass.View    
{
  import flash.display.DisplayObject;
  import KingClass.Model.Vo.IndexVo;
  import org.puremvc.as3.patterns.mediator.Mediator;
        import org.puremvc.as3.interfaces.IMediator;
    
  import KingClass.Event.UIEvent
  import KingClass.View.*;
  import KingClass.Model.*;
  import KingClass.View.Components.TopCom
    
  /**
    * ...
    * @author Never
    */
  public class TopMediator extends Mediator implements IMediator
  {
    public static const NAME:String = "TopMediator";
    /*因爲Mediator也會經常和Proxy交互,所以經常在Mediator的構造方法中取得Proxy實例的引用並保存在Mediator的屬性中,這樣避免頻繁的獲取Proxy實例*/
    private var _showProxy:ShowProxy = new ShowProxy();
    
    public function TopMediator(viewComponent:DisplayObject = null)
                {
                        super(NAME, viewComponent);
        
      viewComponent.addEventListener(TopCom.EVENT_BTN_CLICK, onEventClick );
        
      var _TopCom:TopCom = new TopCom();    
      _TopCom.y = 180;
      main.addChild(_TopCom);    
    }
    
    
    private function get main():Main {    
      return viewComponent as Main;    
    }    
    
    private function onEventClick(e:UIEvent = null):void {    
      _showProxy.newData=new IndexVo(e.data as int)
    }
     
    //end class
  }
}
 
最後是
Proxy

Proxy是有狀態的,當狀態發生變化時發Mediator,將數據的變化反映到視圖。Proxy可能會提供訪問Data Object部分屬性或方法的API,也可能直接提供Data Object的引用。如果提供了更新Data Object的方法,那麼在數據被修改時可能會發送一個Notifidation通知系統的其它部分。Proxy不監聽Notification,也永遠不會被通知,因爲Proxy並不關心View的狀態。但是,Proxy提供方法和屬性讓其它角色更新數據。View本質上是顯示Model的數據並讓用戶能與之交互,我們期望一種單向依賴,即View依賴於Model,而Model卻不依賴於ViewView必須知道Model的數據是什麼,但Model卻並不需要知道View的任何內容。
我們在這個例子中定義了一個ShowProxy.as的類,它的底層數據來自於IndexVo.as
 
ShowProxy.as(當數據層發生改變時 它發出一個notification,通知view做出新的變化,比如切換界面)
package KingClass.Model    
{
  import KingClass.Model.Vo.IndexVo;
  import org.puremvc.as3.patterns.observer.Notification;
        import org.puremvc.as3.patterns.proxy.Proxy;
        import org.puremvc.as3.interfaces.IProxy;
    
  import KingClass.ApplicationFacade;
    
  /**
    * ...
    * @author Never
    */
  public class ShowProxy extends Proxy implements IProxy
  {
    public static const NAME:String = "ShowProxy";
    private var newdata:Object;

    public function ShowProxy(str:String=""):void    
    {
      super(NAME, str);    
    }
    
    //Proxy是有狀態的,當數據發生改變時 我們發送一個Notification。
    public function set newData(n:Object):void{        
                        newdata = n;
        
      sendNotification(ApplicationFacade.CHANGETABLE,this)
                }
    
                /* 添加項 */        
                public function get newData():Object{        
                        return this.newdata;
                }    
    
  }
}
 
IndexVo.as(這是proxy操控的數據層)
package KingClass.Model.Vo    
{
    
  /**
    * ...
    * @author Never
    */
  public class IndexVo extends Object
  {
    private var _index:int;
    
    public function IndexVo(n:int)    
    {
      this.index=n
    }
    
    public function set index(n:int):void {
      this._index = n;
    }
    
    public function get index():int{
      return this._index;
    }
    
    
  }
}
 
另外還需要一個ChangeComman.as,他是註冊一個新的proxy。即我們需要的ChangeComman.這在proxy數據發生變化時,已經發出notification了。
package KingClass.Controller    
{
  import org.puremvc.as3.patterns.command.SimpleCommand;
  import org.puremvc.as3.interfaces.ICommand;    
  import org.puremvc.as3.interfaces.INotification;    

  import KingClass.View.Components.TopCom;
  import KingClass.Model.ShowProxy;
  /**
    * ...
    * @author Never
    */
  public class ChangeComman extends SimpleCommand
  {
    
    public function ChangeComman()    
    {    
    }

    override public function execute(notification:INotification):void        
                {
                        /* 註冊Model */        
      var showProxy:ShowProxy = notification.getBody() as ShowProxy;
                        facade.registerProxy(showProxy);        
                }
    
    //end class
  }    
}

 
當然,源碼會奉上~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章