zoukankan      html  css  js  c++  java
  • PureMVC(AS3)剖析:实例

    PureMVCAS3)剖析:实例

    实例

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

    1.  PureMVC模块划分

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

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

     

    1PureMVC项目的模块划分

    ProxyMediatorCommand分别对应MVC中的ModelViewController,也分别有对应的单例管理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(控制器),建立CommandNotification 名之间的映射。

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

    n  为了使ApplicationFacade结构更清晰,简洁。将注册CommandProxyView&Mediator的工作抽离到BootstrapCommandsBootstrapModelsBootstrapViewMediators去做。

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

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

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

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

     

    2 StartupCommand包含3个子命令BootstrapCommandsBootstrapModelsBootstrapViewMediators

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

     

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

     

    3.  推荐PureMVC结构

     

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

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

    4.  PureMVC模块间通信

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

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

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

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

     

    5PureMVC之间的通信

    5.  PureMVC实例:连连看游戏

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

    需求

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

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

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

    设计

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

    关卡数据的几点说明:

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

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

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

    关卡难度递进设定:

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

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

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

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

    实现

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

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

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

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

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

    n  关卡选择模块包括:

    framework.view.componets.ChooseLevCanvasMediator

    framework.view.componets.ui.ChooseLevCanvas

    framework.controller.commands.ChooseLevCommand

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

    ChooseLevCanvasChooseLevCanvasMediator组成ViewChooseLevCanvas负责具体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,生成、存储、重排具体关卡的数据,负责数据相关操作。

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

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

    这里涉及到的通信方式有,通知flash内置事件(xxxCanvaxxxCanvasMediator

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

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

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

    注意点3CommandProxyMediator

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

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

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

    注意点4:一般一个MediatorhandleNotification方法)处理的Notification应该在45个之内。

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

    注意点5:应该避免MediatorProxy 直接交互。

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

    参考资料

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

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

    [3]     PureMVC_Implementation_Idioms_and_Best_Practices_cn

     

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

     
  • 相关阅读:
    Ubuntu 14.04 卸载通过源码安装的库
    Ubuntu 14.04 indigo 相关依赖
    Ubuntu 14.04 indigo 安装 cartographer 1.0.0
    Ubuntu 14.04 改变文件或者文件夹的拥有者
    安装cartographer遇到Unrecognized syntax identifier "proto3". This parser only recognizes "proto2"问题
    Unrecognized syntax identifier "proto3". This parser only recognizes "proto2". ”问题解决方法
    查看所有用户组,用户名
    1卸载ROS
    Ubuntu14.04 软件安装卸载
    Ubuntu14.04系统显示器不自动休眠修改
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2881608.html
Copyright © 2011-2022 走看看