好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

PureMVC(AS3)剖析:实例

PureMVC(AS3)剖析:实例

PureMVC ( AS3 )剖析:实例

实例

上篇 介绍了 MVC 的思维方式“代码重用( code reusability )、关注点分离( separation of concerns , SoC )”,并介绍了 PureMVC 框架的设计。本篇从一个实例出发,详细介绍 PureMVC 框架中的元素、推荐的项目目录组织方式、代码格式等等。

1.    PureMVC 模块划分

上篇中介绍了 PureMVC 框架设计中存在的角色,这里先回顾一下:经典 MVC 元设计模式中的三部分由三个单例类管理,分别是 Model 、 View 和 Controller 。 PureMVC 中还有另外一个单例类—— Fa?ade , Fa?ade 提供了与核心层通信的唯一接口。 这 4 个单例类构件了 PureMVC 的骨架 。

实际上,我们知道一个游戏或项目由多个模块组成(如登陆 / 注册模块、主场景模块、关系链模块等等),每个模块通常都是单独的 Model 、 View 、 Controller 。 PureMVC 的那 4 个单例类是满足不了这样的需求的,但是它提供了 Proxy 、 Mediator 、 Command 来解决这个问题。

 

图 1 : PureMVC 项目的模块划分

Proxy 、 Mediator 、 Command 分别对应 MVC 中的 Model 、 View 、 Controller ,也分别有对应的单例管理 Model 保存所有的 Proxy 引用、 View 保存所有的 Mediator 引用、 Controller 保存所有的 Command 映射:

l    Proxy : Proxy  负责操作数据模型,与远程服务通信存取数据;

l    Mediator:  Mediator 操作具体的视图组件 UI ,包括:添加事件监听器,发送或接收  Notification  ,直接改变视图组件的状态;

l    Command:  Command  可以获取  Proxy  对象并与之交互,发送  Notification ,执行其他的  Command 。

2.    推荐 PureMVC 初始化流程

PureMVC 框架的入口是继承 Fa?ade 的子类: ApplicationFacade (这个随你喜欢, startUp() 方法启动初始化框架。

ApplicationFacade 类:

        public class  ApplicationFacade  extends  Facade  implements  IFacade

          {

                    private static const STARTUP:String = "startup";

                  

                    public static function getInstance():ApplicationFacade

                    {

                             if (instance == null)

                                      instance = new ApplicationFacade();

                             return instance as ApplicationFacade;

                    }

                  

                    override protected function  initializeController ():void

                    {

                             super.initializeController();

                             registerCommand(STARTUP, StartupCommand);

                    }

                  

                    public function  startUp (rootView:DisplayObjectContainer):void

                    {

                             sendNotification(STARTUP, rootView);

                             removeCommand(STARTUP); //PureMVC 初始化完成,注销 STARUP 命令

                    }

这个类有几点需要说明的:

n    它是 PureMVC 应用程序的入口。 ApplicationFacade  类对象负责初始化 Controller (控制器),建立 Command 与 Notification  名之间的映射。

n    ApplicationFacade  类仅定义 Notification (通知)常量: STARTUP   ( private ),标识应用程序启动,其它 Notification (通知)常量抽离到 ApplicationConstants 中定义,这样更简洁、清晰。

n    为了使 ApplicationFacade 结构更清晰,简洁。将注册 Command 、 Proxy 、 View&Mediator 的工作抽离到 BootstrapCommands 、 BootstrapModels 、 BootstrapViewMediators 去做。

l    BootstrapCommands :初始化应用程序事件与 Command 之间的映射关系;

l    BootstrapModels : Model  初始化,初始化应用程序启动过程中需要用到的 Proxy ,并注册;

l    BootstrapViewMediators : View  初始化,唯一创建并注册 ApplicationMediator ,它包含其他所有 View Component 并在启动时创建它们。

调用 startUp() 启动应用程序,发送 STARTUP 命令;然后触发 StartupCommand ,它包含三个子 command 执行(这里借鉴 Robotlegs 的思想,将 Command 、 Model 、 ViewMediator 初始化工作分离,使得程序结构更清晰。)

 

图 2 :  StartupCommand 包含 3 个子命令 BootstrapCommands 、 BootstrapModels 、 BootstrapViewMediators

简而言之,框架初始化流程可以表示如下:

 

图 3 :  PureMVC 应用程序框架初始化流程

 

3.    推荐 PureMVC 结构

 

图 4 :推荐目录结构(图为连连看例子的目录结构)

推荐目录结构为,按 MVC 分为 3 个目录: model 、 view 、 controller 。 Model 下面有定义 vo 的子目录, view 下面有定义 UI 界面的子目录 ui 等, controller 下面有定义初始化的子命令目录 boostraps 。实际项目中的基本上每个功能模块,在三个目录下对应的类。

4.    PureMVC 模块间通信

当一个模块需要与其它模块交互时,可以通过 发送 / 接收 Notification 或者通过 fa?ade 的 facade.retrieveMediator 、 facade.retrieveProxy 检索到指定模块,然后调用相应接口。

Flash 事件和 PureMVC 通知的主要差异是:事件遵循“责任链”模式,在显示层级中“冒泡”直到有父组件处理它;而通知遵循“发布 / 订阅”模式。使用通知进行通信, PureMVC 各模块之间不需要建立父子关系。

通知并不是事件的替代物。 一般情况下, Mediator 给其视图组件添加事件侦听器,按常用方式处理,然后给目标 Command 广播 Notice ,或与其他 Mediator 通信。 Proxy 通过广播 Notice ,与 Command 实例和 Mediator 通信。

推荐使用 Notification 机制,但是全部使用 Notification 这种强松耦合模式:①强松耦合加重通信次数;②带反馈数据的通信加重通信负担。 适当使用直接通信方式。

 

图 5 : PureMVC 之间的通信

5.    PureMVC 实例:连连看游戏

首先声明“连连看”游戏并非很适合使用 PureMVC 框架,因为它本身并不复杂,而且没有需要复用的逻辑代码等。这里通过这样一个不太复杂的小游戏,介绍 PureMVC 。

需求

《连连看》是一款操作非常简单的小游戏,它的玩法就是用直线将两个相同的图标消掉,分为十关,难度递进。

【概要】玩家可以将  2  个相同图案的对子连接起来,连接线不多于  3  根直线,就可以成功将对子消除。

【操作】第一次使用鼠标点击棋盘中的棋子,该棋子此时为“被选中”,以特殊方式显示;再次以鼠标点击其他棋子,若该棋子与被选中的棋子图案相同,且把第一个棋子到第二个棋子连起来,中间的直线不超过  3  根,则消掉这一对棋子,否则第一颗棋子恢复成未被选中状态,而第二颗棋子变成被选中状态

设计

整个游戏分为 2 个模块:关卡选择模块、关卡具体模块。关卡选择模块,类似一个菜单呈现 10 个关卡供玩家选择;关卡具体模块,呈现特定关卡的详细信息,如需要消除的棋子、总时间、重排棋子按钮、获取提示按钮、暂停按钮等等。

关卡数据的几点说明:

n    关卡数据可以通过关卡编辑器生成配置文件,然后读取配置文件即可。这样关卡更可控,且可以摆放成各种形状(心形、回形等等)的数据。

n    如果做成网络版的,关卡数据也可以通过服务器端返回。

本实例为了简单,关卡数据根据等级随机生成 10 种图片,数量固定为 40 个。

关卡难度递进设定:

n    第一,从时间递减来增加难度, 30 * (11 - level) 。

n    第二,从可以重新摆放棋子、获取提示次数来体现。

n    如果作为一个商用连连看,还可以通过棋子的种类数量、定时随机重排增加难度。

判断连通算法,可以使用多种: 分支界定判断 、 广度优先搜索法 、 四个方向的 A* 算法 等等,例子不考虑性能简单的使用了分支界定判断,而且这里也不会深入介绍,毕竟我的目的不是介绍连连看算法,有兴趣的自行了解。

实现

详细代码我已放到 GitHub : https://github.com/saylorzhu/linkupGame ,自行前往查看。我们做技术的,看代码就可以了解如何使用 PureMVC 了,看到这里更推荐你去看代码。下面我只介绍代码的几个 PureMVC 实现的关键地方。

注意点 1 : PureMVC 框架初始化流程,及代码组织

这也是我想推送给大家的,框架初始化流程可参见【 2.  推荐 PureMVC 初始化流程】,代码组织方法可参见【 3.  推荐 PureMVC 结构】。

注意点 2 :模块划分与通信

游戏分为 2 个模块:关卡选择模块、关卡具体模块。

n    关卡选择模块包括:

framework.view.componets.ChooseLevCanvasMediator

framework.view.componets.ui.ChooseLevCanvas

framework.controller.commands.ChooseLevCommand

该模块不用存储数据,没有 Proxy 。

ChooseLevCanvas 、 ChooseLevCanvasMediator 组成 View , ChooseLevCanvas 负责具体 UI 展示和操作响应, ChooseLevCanvasMediator 负责将来自用户操作的事件转发给 PureMVC 框架并将来自框架的事件转发给 ChooseLevCanvas 。

ChooseLevCommand 由玩家选择具体关卡事件 ApplicationConstants.SELECT_LEVEL 触发,该 Command 调用 LevelProxy 的接口生成关卡数据,然后通知到“关卡具体模块”开始游戏。

n    关卡具体模块包括:

framework.view.componets.LevelCanvasMediator

framework.view.componets.ui.LevelCanvas

framework.model.LevelProxy

framework.controller.commands.ReSortCommand

LevelProxy  属于 Model ,生成、存储、重排具体关卡的数据,负责数据相关操作。

LevelCanvas 与 LevelCanvasMediator 组成 View , LevelCanvas 负责具体 UI 展示和响应玩家操作, LevelCanvasMediator 负责将来自用户操作的事件转发给 PureMVC 框架并将来自框架的事件转发给 LevelCanvas 。

ReSortCommand 由玩家点击重排按钮触发,该 Command 调用 LevelProxy 的接口重排关卡中的棋子。

这里涉及到的通信方式有, 通知 、 flash 内置事件( xxxCanva 与 xxxCanvasMediator ) 。

Command 需要侦听通知,需要在 framework.controller.boostraps.BootstrapCommands 中使用 registerCommand 注册;

xxxCanvasMediator 需要侦听通知,需要在对应 Mediator 中使用 listNotificationInterests 注册,并重写 handleNotification 处理。

模块间通信可参见【 4.PureMVC 模块见通信】。

注意点 3 : Command 与 Proxy 、 Mediator

Command 管理应用程序的  Business Logic (业务逻辑), 要协调 Model  与视图状态 。

Model  通过使用  Proxy  来保证数据的完整性、一致性   。 Proxy  集中程序的 Domain Logic (域逻辑),并对外公布操作数据对象的 API 。它封装了所有对数据模型的操作,不管数据是客户端还是服务器端的。

Mediator  和 Proxy  可以提供一些操作接口让 Command  调用来管理 View Component  和 Data Object  ,同时对  Command 隐藏具体操作的细节。

注意点 4 :一般一个 Mediator ( handleNotification 方法)处理的 Notification 应该在 4 、 5 个之内。

还要注意的是, Mediator 的职责应该要细分。如果处理的 Notification 很多,则意味着 Mediator 需要被拆分,在拆分后的子模块的 Mediator 里处理要比全部放在一起更好。

注意点 5 :应该避免 Mediator 与 Proxy  直接交互。

例子项目中遵从了这个规则,但实际上项目 Mediator 中不可避免需要获取 Proxy 数据,如果每次都通过一个 Notification 去获取数据,然后返回数据给 Mediator , 这样无形中增加了通信次数、带反馈数据的通信加重通信负担 。所以可以适当是的在 Mediator 中 facade.retrieveProxy 获取 Proxy 然后拿到数据,而且从 proxy 直接拿数据,可以保证拿到最新数据。  

参考资料

[1]       PureMVC 官方网站: www.puremvc.org

[2]       Wikipedia : http://zh.wikipedia.org/zh-cn/MVC

[3]       《 PureMVC_Implementation_Idioms_and_Best_Practices_cn 》

 

作者:吴秦
出处:http://www.cnblogs.com/skynet/
本文基于 署名 2.5 中国大陆 许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 吴秦 (包含链接).

 

分类:  网页游戏开发 ,  PureMVC(AS3)剖析

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于PureMVC(AS3)剖析:实例的详细内容...

  阅读:40次