pureMVC简单示例及其原理讲解(用户的添加与删除)开篇

pureMVC是一个 MVC框架,皆在最大限度的减少MVC间的耦合性。本人刚刚接触pureMVC时感到一头雾水,不知从何入手,也不知道从何学习。好在本人有耐性且能看懂英文技术文档,面向对象的编程能力也比较扎实。在这种背景下,终于悟出了pureMVC的原理,能够使用pureMVC进行开发。如果把pureMVC的领悟境界分为若干,我是处于最低境界(潜力很大啊)。好,闲话不说,言归正传。
本示例是在理解了官方示例 EmployeeAdmin示例的基础之上的简化版,用意是为了更好的理解pureMVC。
界面:图片上部控件用于添加用户,下部控件用户显示用户信息和删除已添加的用户
【图1】
 
首先:
pureMVC既然是MVC(Model、View、Controller)框架,那你就必须要记住pureMVC中的四个主要结构类:
  • Proxy(相当于Model)
  • Mediator(相当于View)
  • Command(相当于Controller)
  • Facade(管理Proxy、Mediator和Command的东西)
也许上面小括号中的话说的不严谨,在本示例中 MVC是这样划分的:
  1. Model:由VO(Value Object,即值对象)和Proxy组成;
  2. Mediator:由图1中的两个MXML文件及其对应的Mediator组成;
  3. Command:由一个MacroCommand和若干个SimpleCommand组成;
  4. Facade:即ApplicationFacade;
  5. 启动页:MyPureMVCDemo.mxml文件。
整个示例由以上五个部分组成。具体如图2所示。
【图 2】
 
这里关于 3和4要做一下解释。pureMVC中的Command分为两种:多命令和单一命令,即MacroCommand和SimpleCommand。MacroCommand中通过addSubCommand(SimpleCommandName)来加入子命令,两个Command中的方法都需要被重写override,此外还需要通过facade.registerCommand(...)注册命令。也许这段话我说的不清楚,你只要记住pureMVC框架包含这五个部分就可以了,咱们往下看吧!
 
 
基于PureMVC的一个Flex MP3播放器分析
      做Flex做久了做大了,就会觉得之前写的的Flex代码开始有点乱,哪怕你写的规范了,但总觉得结构松散,维护不方便,相信很多人刚开始做Flex的时候,都是想到什么功能,就写什么功能,或者有些好点的,就先画了个大体的流程图之类的,因为现在Flex普及得还不够,很多人做Flex也是试探阶段,不敢用作商业项目或其它大项目,只会用来试水技术层面的,所以都是做些小应用的多,就会忽略了设计一个比较好的框架来开发。所以Flex的开发框架就应运而生了。目前,好的Flex开发框架还不多,官方有个Cairngorm的框架,可能有些人会说这个框架有点复杂,其实不然,对比起Ruby的Rails,Java的Struts,Spring之类的开发框架,就显得简单得多了。只要清楚了解要MVC的概念,就会对这些框架并不陌生,但是今天的主角不是Cairngorm,而是另一个Flex框架 PureMVC,如果说Cairngorm复杂的话,那么PureMVC就显得简单多了,PureMVC比较轻盈,核心也只有十来个类,是一个轻量级的Flex框架,但PureMVC的通用性还是比较广的,有PHP的,有Java的有Python的。可能直接说框架的使用会比较抽象,那么就由一个实例来开始讲解吧,就用一个PureMVC做的一个MP3播放器。



先来看看 PureMVC 的结构图:



     
在图中, Facade Model View Controller 都是 PureMVC 的四个核心类,都是单例模式的,用户无需操作那 Model,View,Controller 类,而用户只需要操作 Facade 就够了, Facade 类用来管理其它的三个单例类,顾名思义,那三个类都是分别对应 MVC 模式的那三个元素, Facade 也是个单例,它负责创建,激活,调用其它的三个类,管理 MVC 各屋的生命周期。
     
而我们看看Model类,又细分了一个Proxy类出来,我们称其为代理吧,就是对数据模型的一个代理,负责访问我们的数据对象(Data Object)也就是Cairngorm中的ValueObject,其实都是同一个概念。而类结构上,对数据操作的代理Proxy类就只有一个,但可以从我们的应用上又分为Local Proxy,Remote Proxy,其实都只是Proxy ,只是根据用户的应用的不同,在Proxy里面实现不同的功能而已,比如如果你操作本地数据(内存中的数据,并非本地操作系统的文件),你可以写一些VO的getter/setter直接操作数据,而如果是Remote的数据的话,你可以在Proxy类里定义一些HttpService,URLLoader,WebService等等的访问远程数据的API,之后将获取到的远程数据放在VO中。
      在Controller类里分出一个叫Command的类来,直接翻译的话,就是“命令”类,通常这些类都是用来处理一些业务流程,某些算法操作等等的操作。比如现在用户单击了“获取数据”的按钮,程序将从Proxy类里访问服务器,服务器返回数据之后,那些都是程序看得懂的数据,比如是XML,而如果数据结构比较复杂,你不可能直接将数据显示给用户看吧?那就将解析这些数据的工作交给Command来做,比如写一个ParseCommand的类,将获得的XML数据传递给该Command,在Command里进行数据的过滤,排列,整理等等的功能。再将组积好后数据交给Mediator来进行显示,而Mediator,就是下面我们要说的。
     
View 类里分出一个 Mediator 的类,该类是用来对 ViewComponent 操作的,我们暂且叫它 中介类 吧,为什么叫 中介 呢?其实就是用户界面( UI )与程序结构逻辑之间的中介,因为用户在界面上的操作,比如 Button Click 事件不是直接反映到 Command 或者 Proxy 类上的,而是反映给 Mediator 类,在 Mediator 里作一些简单处理,比如验证合法性,触发其它 ViewComponent 的状态等,在这里也会将用户的数据封装在 VO 里面,再交由 Command Proxy 来进一步处理。 基本上Mediator只对用户的操作或用户提交的数据进行封装并简单预处理,而业务逻辑,存储服务的就应交给Command和Proxy来做,这样MVC分工好,使得程序结构比较严紧,可读性强,实现松耦合。当你改变了UI时,只需要对Mediator进行相应的改变就行了,而你改变了业务的逻辑与算法之类的话,也相应的改变Command就可以了,对其它模块的影响不大。
      在上面这个图中,没有列出来的一个很重的类,就是 Notification 类,这个类为什么十分重要,可以说也是PureMVC的润滑剂,因为他是连接MVC各大部分的一个消息机制,就像是Cairngome里面的CairngomeEvent与FrontController,为了实现更好的松耦合,就是靠这个消息机制,因为各大部分中,很少直接的引用调用,而是以“发消息”(或者说是通知吧)来相互数据交流与通讯,这里是很好的使用了“观察者模式”,因此,在某一部分改变的处理逻辑的话,只是它所发送的消息没有改变,或者所侦听的消息没有改变,那么就不会影响到其它部分。
     
另外要注意几点, Command 类是短生命周期的,也就是说,当有消息通知需要用到该 Command 进行处理时, Facade 就会创建这个 Command 类,并将数据传入 Command 里面进行处理,当处理完成后,其生命周期就会结束,所以不要将一些长生命周期的数据存放在 Command 里,比如不要将一些状态数据信息存放在 Command 里面。 还有就是Proxy类只会发送“消息”(通知),而不会接收任何消息,而Mediator与Command则可以发送与接收,所以你不能直接发消息通知Proxy去加载数据,而是通过引用Proxy的实例调用相关的函数。理论就说了一大堆了,我们来看看那个MP3播放器实例吧!

我们先来看看主程序的代码,PureMVC的入口点:
  1  <? xml version="1.0" encoding="utf-8" ?>
 2  < mx:Application  xmlns:mx ="http://www.adobe.com/2006/mxml"
 3                  xmlns:view ="com.jiangzone.flex.pureplayer.view.ui.*"
 4                  verticalGap ="2"
 5                  layout ="vertical"  creationComplete ="fadace.startup(this)"
 6                  backgroundColor ="0x444444">
 7       < mx:Style >
 8          // 这里的 CSS 代码略去
 9       </ mx:Style >
10     
11       < mx:Script >
12           <![CDATA[
13              import com.jiangzone.flex.pureplayer.ApplicationFacade;
14             
15              private var fadace:ApplicationFacade = ApplicationFacade.getInstance();
16             
17           ]]>
18       </ mx:Script >
19       < mx:Box  width ="131">
20           < view:ProgressBoard         id ="progressBoard"  />
21           < view:ControlBoard          id ="controlBoard"  />
22           < view:SongListBoard         id ="songListBoard"  />
23       </ mx:Box >
24     
25  </ mx:Application >


从上面代码我们看到,定义了一个 facade 这个就是 Facade 的一个实例,而 ApplicationFacade 是继承自 Facade 类的,这个就是 PureMVC 的整个架构的控制管理类,因为 Facade 是一个单例,所以不能直接 new 的,所以在 ApplicationFacade 里面定义了一个静态方法来获取它的实例。在程序的 createComplete 事实触发的时候,我们就调用 facade.startup(this) 这个方法,意思就是启动整个框架。
这里的代码都比较简单,我们再来看看 ApplicationFacade 的代码:
 1  package  com.jiangzone.flex.pureplayer
 2  {
 3       import  org.puremvc.as3.interfaces.IFacade;
 4       import  org.puremvc.as3.patterns.facade.Facade;
 5       import  org.puremvc.as3.patterns.observer.Notification;
 6     
 7       import  com.jiangzone.flex.pureplayer.controller.StartupCommand;
 8     
 9       public  class  ApplicationFacade  extends  Facade  implements  IFacade
10      {
11           // Notification name constants
12           public  static  const  STARTUP:String             = "startup";
13         
14         
15           /**
16           * Singleton ApplicationFacade Factory Method
17           */
18           public  static  function getInstance() : ApplicationFacade {
19               if  ( instance ==  null  ) instance =  new  ApplicationFacade( );
20               return  instance as ApplicationFacade;
21          }
22         
23           /**
24           * Start the application
25           */
26            public  function startup(app:Object): void
27           {
28               sendNotification( STARTUP, app );   
29           }
30 
31           /**
32           * Register Commands with the Controller
33           */
34          override  protected  function initializeController( ) :  void
35          {
36               super .initializeController();           
37              registerCommand( STARTUP, StartupCommand );
38          }
39         
40      }
41  }


这里分析一下,在ApplicationFacade类里,我们定义了一个String的常量,这个只是一个消息的类型,跟Flex里的Event的常量一样的,注意,规范化一点的话,应该将消息类型的字符串都定义为常量,而我在后面的代码中为了省事就直接用“XXXXX”这样的字串代替了,还是建义写成静态常量。
我们看到了startup()的代码了,就是在刚才主程序里调用的那个函数,这里接收了一个主程序的引用。
我们还看到了有一个 initializeController( ) 的函数,当这个 ApplicationFacade 被实例化加载的时候,会先自动调用 initializeController( ) 这个函数,所以,我们应当在 ApplicationFacade在被初始化的时候,就对Command进行注册,说就是注册,其实也只是将一个Command与一个消息绑定在一起而已 当发送该消息时,Facade就会自动的找到那个Command并实例化执行。
registerCommand( STARTUP, StartupCommand ); 这句就是对 Command 进行注册的代码, registerCommand 都是父类或接口里面定义的方法,我们先不用管它, STARTUP 就是上面定义的一个常量,表示一个消息的类型, StartupCommand 这个类就是我定义的一个 Command 类,这里说白了就是 STARTUP 这个字符串常量就是一个 Key ,而 StartupCommand 就是一个 Value ,存放在一个数组里面,当有人发送一个 STARTUP 的消息时,程序就自动生成一个 StartupCommand 来处理。
我们再看看 startup() 这个方法,在刚才的主程序里调用这个方法时,传入了一个传入了一个参数 this ,就是主程序本身,在 startup() 方法里面,发送了一个消息 sendNotification( STARTUP, app );    sendNotification() 这个是发送消息的方法,第一个参数是消息的类型,第二个是可选参数,是消息的内容(消息体),在这里,将主程序的引用作为消息体绑在消息里一起发送了。由于之前在初始化的时候将 STARTUP 消息类型与 StartupCommand 绑定在一起了,所以当发送这个消息的时候, StartupCommand 将会被通知,所以这时候,程序的流程就跳入到 StartupCommand 类里面。下面我们来看 StartupCommand 类的内容:
 1  package  com.jiangzone.flex.pureplayer.controller
 2  {
 3       import  org.puremvc.as3.interfaces.ICommand;
 4             // 这里略去一些 import 代码
 5       import  com.jiangzone.flex.pureplayer.model.PlayListProxy;
 6     
 7       public  class  StartupCommand  extends  SimpleCommand  implements  ICommand
 8      {
 9          override  public  function execute( note:INotification ) :  void    
10          {
11               /**
12               *  获取消息体内容,在发送 STARTUP 消息时,将主程序 PurePlayer 作为消息体跟随消息传送
13               */
14              var app:PurePlayer = note.getBody() as PurePlayer;
15             
16               /**
17               *  注册代理( Model
18               */
19              facade.registerProxy( new  SongProxy());
20              facade.registerProxy( new  PlayListProxy());
21               /**
22               *  注册 ViewComponents 或者 UI 组件的中介器。
23               */
24               facade.registerMediator( new  ControlBoardMediator(app.controlBoard));
25               facade.registerMediator(  new  SongListBoardMediator(app.songListBoard));
26               facade.registerMediator( new  ProgressBoardMediator(app.progressBoard));
27               
28               (facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy).loadPlayList();
29          }
30      }
31  }


上面的就是一个 Command 的代码,注意,一个 Command 必需要实现 ICommand 接口,而如果是一个单 Command 的话,就需要继承 SimpleCommand 类,而如果是一个 Command 链的话,就需要实现 MacroCommand ,至于 Command 链,如果有 J2EE 基础的话,也就是 Filter 的过滤器链差不多。这里不多说。大家可以看看 PureMVC 的官方文档与 API!
Command 里,都需要覆盖 execute 这个方法,这个方法就是执行你的逻辑代码的地方,由 Facade 自动调用,当这个 Command 所绑定的消息被发送时, Facade 就会创建一个 Command 实例并调用 execute 方法,方法里还传入一个 INotification 参数,就是你所发送的那个消息,里面包含了消息类型名称与消息体。 在这个Command里,我没有处理什么,因为这个Command用于启动程序框架的,所以只在这里初始化了一些程序需要用到的资源,如注册代理与注册中介器,我们可以看到,注册代理与注册中介器的方法与注册Command的方法不同,注册Command的话,需要一个消息名称与一个Command类绑定,而代理与中介器的注册就不需要与消息绑定,直接将代理与中介器实例化之后进行注册就可以了。这是由于Command的生产控制不是由用户来操作的,是由Facade里面的一个工厂方法来对Command实例化并管理的,所以需要与一个消息名称进行绑定,而代理与中介器就是用户管理的,通常一个代理就对应一个数据结构,如果有几个数据结构都比较简单,就可以在一个Proxy里管理,而同理,中介器也一样,一个中介器对一个Flex组件,但为一个Button建立一个中介器未名太浪费了,所以我这里都是将MP3分成三个部分,控制按钮部分,歌曲列表部分,播放进度部分,三个部分用三个中介器。通常这些中介器或者Proxy创建一次就可以了,Facade会将它它存放在数组中,当需要用到时,再由Facade来获取他们,所以,在注册代理与中介的时候,先实例化它们再注册!因为Command是短生命周期,而Proxy与Mediator是长生命周期,所以这里与Command有点区别。在实例化中介器的时候,我传入一个app.controlBoard的值:
new ControlBoardMediator(app.controlBoard),就是说,我这个中介器是对应app.controlBoard这个控件,app就是主程序。
当所有需要的资源都注册好后,我执行了下面一句代码:
 (facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy).loadPlayList();
之前讲到,注册代理时,将代理的实例进行注册,实际上就只是在 Facade 里将这个代理实例放进数组里而已,所以用 facade.retrieveProxy() 这个方法可以再次获得那个实例的引用,再调用这个代理里的一个方法 loadPlayList() 来进行加载播放列表。 上上上面已经说过,因为Proxy是只可以发信息,不可以收信息,所以你叫Proxy工作的话,只好得到它的引用再调用它的方法来控件它的工作。注意,在Facade重新获得代理的方法里facade.retrieveProxy(PlayListProxy.NAME) as PlayListProxy  你需要指定一个字符串来获取某一个代理,在编写每一个代理时,都要为它指定一个name的字符串,而且是代理的唯一标识!这个时候,程序的流程就会跳到代理里运行loadPlayList()这个方法。下面,我们来看看PlayListProxy的代码:
 1  package  com.jiangzone.flex.pureplayer.model
 2  {
 3       import  org.puremvc.as3.interfaces.IProxy;
 4             // 省略import代码
 5       import  flash.xml.XMLNode;
 6 
 7       public  class  PlayListProxy  extends  Proxy  implements  IProxy
 8      {
 9           // 定义一个代理的名字,唯一的标识
10           public  static  const  NAME:String = 'PlayListProxy';
11           // 定义一个HttpService,用于获取远程的数据
12           private  var hs:HTTPService;
13         
14           public  function PlayListProxy(): void {
15               super (NAME, new  Array());
16              hs =  new  HTTPService();
17              hs.addEventListener(ResultEvent.RESULT,onResult);
18              hs.addEventListener(FaultEvent.FAULT,onFault);
19          }
20         
21           public  function get playList():Array{
22               return  data as Array;
23          }
24         
25           public  function loadPlayList(url:String = 'jiang/pureplayer/data/playlist.xml'): void {
26              hs.method = "GET";
27              hs.resultFormat = "xml";
28              hs.url = url + '?ranid=' + ( new  Date()).time;
29              hs.send();
30          }
31         
32           private  function onFault(e:FaultEvent): void {
33 
34          }
35         
36           private  function onResult(e:ResultEvent): void {
37              var arr:Array = data as Array;
38              var xmlNode:XMLNode = e.result as XMLNode;
39               for (var i:String in xmlNode.childNodes){
40                  var obj:Object =  new  Object();
41                  var node:XMLNode = xmlNode.childNodes[i];
42                  obj["label"] = node.attributes.label;
43                  obj["data"] = node.attributes.data;
44                  arr.push(obj);
45              }
46              sendNotification("GET_PLAYLIST_COMPLETE",data);
47          }
48      }
49  }

 


来分析一下代码,在该代理被实例化时,会调用super(NAME,new Array());这个父类的方法,其实Proxy的构造函数接收两个参数,一个是Proxy的唯一标识名字,另一个就是所需要作代理的数据,是一个Object,就是说,你的这个Proxy类要对哪些数据作代理呢?就是这个值传入的,在Proxy基类里面有一个data的属性,这个属性就是存放你的实际数据,所以在我的这个PlayListProxy构造时,我创建了一个Array来作为我的数据,因为我这个代理,是代理一个播放列表数据的,所以我将用Array来存放我的播放列表数据。所以就将new Array()的值交给父类构造器里,父类构造器将会对该Array存放在data这个变量属性里。由于data是Object类型的,所以我们获取这个data的时候,还要对其转换成相应的类型,所以为了方便,我写了一个getter方法来封装这个操作:
1  public  function get playList():Array{
2       return  data as Array;
3  }

以后可以直接调用playList属性来获取Array类型的数据了。
而在 loadPlayList 这个函数里,接收一个可选参数 url ,通过 HttpService 来获取该 url 中的 xml 数据。
按照上面说的那样, Proxy 只有一个,但你可以按不同用途分为 Local Proxy ,与 Remote Proxy ,而这里它的作用就是 Remote Proxy ,因为他是操作远程数据。
当接收数据成功时,调用了 onResult 方法,里面进行了XML简单的分析,其实可以将该分析操作交给一个Command来完成,但是这里确实是太简单的分析了,就没有必交给Command了,自已来完成吧。当解析完成时,发送了一个消息sendNotification("GET_PLAYLIST_COMPLETE",data);
这里要说明一下,这里用了发消息来通知其它模块说我已获得数据了,你们谁对这个数据有兴趣就拿去吧。(本人觉得这样理解更有趣并容易理解)由于是这个机制,所以无论你界面怎样改变,中介器怎样改变,都不会影响到我Proxy,因为我获得数据时,我不用引用你某一个中介器(如果中介器改变了,则同时要修改Proxy的代码),我只发送一个消息,你们要则要,不要则罢,所以你界面如何改变的话,只要接收这个消息就可以同样的得到了数据,而不用因界面的修改而修改Proxy。这样就可以将Mediator与Proxy松耦了。
至于,是谁对这个“GET_PLAYLIST_COMPLETE”感兴趣呢?我在上上上面说过,Proxy只会发,不会收,所以肯定不是其它Proxy对这消息有兴趣,而Command么,Command感兴趣的消息都是在Facade里给绑定的,而我们上上上面的代码中,Facade只绑定了STARTUP这个消息,所以现在唯一下来的,就是中介器了,因为中介器也是可以收与发消息的。如果一个中介器(或者说一个界面组件吧)对一个消息感兴趣的话,那就需要在中介器的类里面定义这些感兴趣的消息,下面我们来看看一个ControlBoardMediator的中介器的代码:
  1  package  com.jiangzone.flex.pureplayer.view
 2  {
 3       import  org.puremvc.as3.patterns.mediator.Mediator;
 4       import  org.puremvc.as3.interfaces.IMediator;
 5       import  com.jiangzone.flex.pureplayer.view.ui.SongListBoard;
 6       import  flash.events.MouseEvent;
 7       import  mx.events.ListEvent;
 8       import  org.puremvc.as3.interfaces.INotification;
 9       import  mx.controls.List;
10       import  mx.collections.ArrayCollection;
11 
12       public  class  SongListBoardMediator  extends  Mediator  implements  IMediator
13      {
14           public  static  const  NAME:String = "SongListBoardMediator";
15         
16           public  function SongListBoardMediator(vc:Object): void {
17               super (NAME,vc);
18              songListBoard.songList.doubleClickEnabled =  true ;
19             
20              songListBoard.songList.addEventListener(ListEvent.ITEM_DOUBLE_CLICK,onDoubleClick);
21          }
22         
23           public  function get songListBoard():SongListBoard{
24               return  viewComponent as SongListBoard;
25          }
26         
27           public  function get songList():List{
28               return  songListBoard.songList;
29          }
30         
31           private  function onDoubleClick(e:ListEvent): void {
32              var str:String = (e.target.selectedItem.data as String);
33              sendNotification("GET_SONG_URL_COMPLETE",str);
34          }
35         
36          override  public  function listNotificationInterests():Array{
37               return  [
38                         "GET_SONG_URL",
39                         "GET_PREV_URL",
40                         "GET_NEXT_URL",
41                         "GET_PLAYLIST_COMPLETE"
42                     ];
43          }
44         
45          override  public  function handleNotification(note:INotification): void {
46               switch (note.getName()){
47                   case  "GET_SONG_URL":
48                       if (songList.selectedItem)
49 
50 
51                          sendNotification("GET_SONG_URL_COMPLETE",songList.selectedItem.data as String);
52                       break ;
53                   case  "GET_PREV_URL":
54                       if (songList.selectedItem){
55                          var i: int  = songList.selectedIndex;
56                          i -= 1;
57                           if (i<0) i = (songList.dataProvider as ArrayCollection).length - 1;
58                          songList.selectedIndex = i;
59                          sendNotification("GET_PREV_URL_COMPLETE",songList.selectedItem.data as String);
60                      }
61                       break ;
62                   case  "GET_NEXT_URL":
63                       if (songList.selectedItem){
64                          var i: int  = songList.selectedIndex;
65                          i = (i + 1) % (songList.dataProvider as ArrayCollection).length;
66                          songList.selectedIndex = i;
67                          sendNotification("GET_PREV_URL_COMPLETE",songList.selectedItem.data as String);
68                      }
69                       break ;
70                   case  "GET_PLAYLIST_COMPLETE":
71                      var arr:Array = note.getBody() as Array;
72                      songList.dataProvider = arr;
73              }
74          }
75      }
76  }


在这份代码中,我们主要看看几个方法函数,其它的都只是处理逻辑,控制Sound的播放什么的,与PureMVC关系不大了。我们主要看看这几个方法:
override public function listNotificationInterests():Array
override public function handleNotification(note:INotification):void
先说第一个方法,这个方法返回的是一个数组,我们上面说到,怎么知道中介器对哪些消息感兴趣呢?就在这个方法里设置了,这些都是接口里的方法,所以需要override,在这个方法里,直接返回一个字符串数组就可以了,而那些字符串,就是你的消息名称 的字符串,刚才Proxy中,处理完数据后,发了一个“GET_PLAYLIST_COMPLETE”的消息,并将处理好的数据作为消息体一起发送出去了。
而在这个 Mediator 里的 listNotificationInterests 里,返回一个
1  return  [
2      "GET_SONG_URL",
3      "GET_PREV_URL",
4      "GET_NEXT_URL",
5      "GET_PLAYLIST_COMPLETE"
6  ];

看到没有?那个数组里面包含了 GET_PLAYLIST_COMPLETE 这个消息名称字符串。所以,当有人发送这个消息时,这个中介器就会进行响应,至于对这个消息的响应程序,就在
override public function handleNotification(note:INotification):void
这个方法里面写上消息响应代码。
在响应函数里,都用switch(note.getName())来区分处理它所接收到的消息的名称,再处以不同的处理代码。

好了,基本上,整个PureMVC的结构就这样了,流程是比较简单,就是用消息(Notification)来围绕MVC各个部分模块来开发。这个程序还有其它的中介器类,代理类还有其它的类就不一一列出来了,反正PureMVC工作方式都是一样的,只是对应的功能逻辑不一样。

你可能感兴趣的:(mvc)