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)剖析:实例的详细内容...