PureMVC框架.docx

上传人:b****6 文档编号:3919135 上传时间:2022-11-26 格式:DOCX 页数:13 大小:95.97KB
下载 相关 举报
PureMVC框架.docx_第1页
第1页 / 共13页
PureMVC框架.docx_第2页
第2页 / 共13页
PureMVC框架.docx_第3页
第3页 / 共13页
PureMVC框架.docx_第4页
第4页 / 共13页
PureMVC框架.docx_第5页
第5页 / 共13页
点击查看更多>>
下载资源
资源描述

PureMVC框架.docx

《PureMVC框架.docx》由会员分享,可在线阅读,更多相关《PureMVC框架.docx(13页珍藏版)》请在冰豆网上搜索。

PureMVC框架.docx

PureMVC框架

pureMVC简单示例及其原理讲解——开篇

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(ValueObject,即值对象)和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的一个FlexMP3播放器分析

     做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类出来,我们称其为代理吧,就是对数据模型的一个代理,负责访问我们的数据对象(DataObject)也就是Cairngorm中的ValueObject,其实都是同一个概念。

而类结构上,对数据操作的代理Proxy类就只有一个,但可以从我们的应用上又分为LocalProxy,RemoteProxy,其实都只是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 

Application xmlns:

mx="

 3                 xmlns:

view="com.jiangzone.flex.pureplayer.view.ui.*"

 4                 verticalGap="2"

 5                 layout="vertical" creationComplete="fadace.startup(this)"

 6                 backgroundColor="0x444444">

 7     

Style>

 8         //这里的CSS代码略去

 9     

Style>

10    

11     

Script>

12         

[CDATA[

13             import com.jiangzone.flex.pureplayer.ApplicationFacade;

14            

15             private var fadace:

ApplicationFacade = ApplicationFacade.getInstance();

16            

17         ]]>

18     

Script>

19     

Box width="131">

20         

ProgressBoard        id="progressBoard" />

21         

ControlBoard         id="controlBoard" />

22         

SongListBoard        id="songListBoard" />

23     

Box>

24    

25 

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的值:

newControlBoardMediator(app.controlBoard),就是说,我这个中介器是对应app.controlBoard这个控件,app就是主程序。

当所有需要的资源都注册好后,我执行了下面一句代码:

 (facade.retrieveProxy(PlayListProxy.NAME)asPlayListProxy).loadPlayList();

之前讲到,注册代理时,将代理的实例进行注册,实际上就只是在Facade里将这个代理实例放进数组里而已,所以用facade.retrieveProxy()这个方法可以再次获得那个实例的引用,再调用这个代理里的一个方法loadPlayList()来进行加载播放列表。

上上上面已经说过,因为Proxy是只可以发信息,不可以收信息,所以你叫Proxy工作的话,只好得到它的引用再调用它的方法来控件它的工作。

注意,在Facade重新获得代理的方法里facade.retrieveProxy(PlayListProxy.NAME)asPlayListProxy 你需要指定一个字符串来获取某一个代理,在编

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1