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
  }    
}
当然,源码会奉上~
 
接下来是: