puremvc的unity案例_游戏防闪退框架

puremvc的unity案例_游戏防闪退框架作者:吴秦出处:http://www.cnblogs.com/skynet/本文基于署名2.5中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名吴秦(包含链接).参考资料[1]    PureMVC官方网站:www.puremvc.org[2]    Wikipedia:http://zh.wikipedia.org/zh-cn/MVC[

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

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

参考资料

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

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

[3]     PureMVC_Implementation_Idioms_and_Best_Practices_cn

 

PureMVC(AS3)剖析:开篇

2012-12-29 00:24 by 吴秦, 5768 阅读, 8 评论, 收藏编辑

PureMVCAS3)剖析:开篇

缘起

自从事flash webgame开发起,3个项目都使用到了MVC模式:1个自己构建的MVC没有使用外部框架;2个使用的PureMVC框架。对PureMVC也有了一定的深度的认识,是时候来总结、吐槽下。现在网上已经流传很多关于PureMVC的资源,但是总觉得深度不够,故有了现在这个系列,我尽量带着自己的思考深入的介绍PureMVC,同时也能引起大家的思考。这里我并不是一味的说PureMVC有多好,它也有值得质疑和使用不爽的地方。

MVC思维

要了解PureMVC框架,首先得有MVC的思维方式,用MVC的思想去思考问题,分解需求、实现需求。MVC背后的核心思想是:

代码重用(code reusability)、关注点分离(separation of concernsSoC

MVC思维围绕这两点转,下面举个例子说明。对于一个游戏或软件来说,给人的第一感觉就是界面(视图View),它展示了一些数据等信息给用户。这些界面上的数据可以存储在视图View属性或定义的变量中,如游戏中用户信息栏中显示玩家的等级、经验、昵称:

clip_image002

图:玩家信息栏界面

这样数据跟视图绑定在一起,其它界面视图(玩家详细信息栏)想要等级、经验、昵称等数据需要访问玩家信息栏界面,又或者从后台重新拉取。

clip_image004

图:玩家详细信息界面

这里违反了“代码重用和关注点分离”思想,需要把数据独立出来保存在一个与View无关地方模型(Model),多个视图可以共用一份数据。这样代码即可重用,关注点也实现了分离, View只需要关注如何展示信息, Model只需要关注数据本身及相关逻辑。

上面达到了界面和数据分离之后,但是思考这样一个过程:用户操作了View需要更新Model,同理Model改变了需要更新View的显示,该如何去做?可能会想到用户操作View时直接调用Model接口去更新数据,这时其他共用这个Model的视图View如何同步更新又是一个问题。Model改变了数据,直接调用View接口更新显示的话,它必须要知道所有的共用这个模型Model的视图View

这样视图View与模型Model就不能达到彻底的“代码重用和关注点分离”。MVC的指导思想就是把这个部分代码独立出来称为控制器Controller。模型和视图从此也只关心控制器,而不关心对方。他们的代码都是处理自己的事情,别人的事情全部交给控制器去办,这使得他们自己的功能也非常独立,减少了需要考虑的要素。

在这之后,三者的关系只存在简单的调用代码。那么为了能够彻底的分离和解耦,就可以将调用代码改为事件或者其他的动态形式(如发布/订阅、依赖注入等等),常用的MVC框架都实现了这样的功能。

clip_image006

图:MVC结构图(实线——>表示依赖;虚线—->表示事件/通知等)

l  模型(Model):“数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。(比较:观察者模式(软件设计模式))

l  视图(View):视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。

l  控制器(Controller):控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变

请大家记住“MVC思维“及上面这些描述,后面还会引用这些。

PureMVC框架

PureMVC框架的目标很明确,即把程序分为低耦合的三层:ModelViewController。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。

PureMVC实现的经典MVC元设计模式中,这三部分由三个单例模式类管理,分别是Model ViewController。三者合称为核心层核心角色PureMVC中还有另外一个单例模式类——FaçadeFaçade提供了与核心层通信的唯一接口,以简化开发复杂度

clip_image008

图: PureMVC设计示意图(摘自官方网站

从设计图中可以清楚看到,除了核心层、Façade之外,还有MediatorProxyCommand

l  Proxy: Model 保存对 Proxy 对象的引用,Proxy 负责操作数据模型,与远程服务通信存取数据。

l  Mediator: View 保存对 Mediator 对象的引用。由 Mediator 对象来操作具体的视图组件,包括:添加事件监听器,发送或接收 Notification ,直接改变视图组件的状态。这样做实现了把视图和控制它的逻辑分离开来。

l  Command: Controller 保存所有 Command 的映射。Command 类是无状态的,只在需要时才被创建Command 可以获取 Proxy 对象并与之交互,发送 Notification,执行其他的 Command

为了彻底解耦,避免直接的函数调用,PureMVC使用观察者模式(发布/订阅)的形式传递消息。PureMVC 的通信并不采用 Flash EventDispatcher/Event,因为PureMVC 可能运行在没有 Flash Event EventDispatcher 类的环境中,它的通信是使用观察者模式以一种松耦合的方式来实现的。

你可以不用关心 PureMVC Observer/Notification 机制是怎么实现的,它已经在框架内部实现了。你只需要使用一个非常简单的方法从 Proxy, Mediator, Command Facade 发送 Notification,甚至不需要创建一个Notification 实例。

下面是我对PureMVC的理解画的设计示意图:

clip_image010

图: PureMVC另种示意图

PureMVC(AS3)剖析:实例

2013-01-29 12:34 by 吴秦, 8790 阅读, 18 评论, 收藏编辑

PureMVCAS3)剖析:实例

实例

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

1.  PureMVC模块划分

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

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

clip_image002

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初始化工作分离,使得程序结构更清晰。)

clip_image004

2 StartupCommand包含3个子命令BootstrapCommandsBootstrapModelsBootstrapViewMediators

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

clip_image006

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

 

3.  推荐PureMVC结构

clip_image007

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这种强松耦合模式:①强松耦合加重通信次数;②带反馈数据的通信加重通信负担。适当使用直接通信方式。

clip_image009

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直接拿数据,可以保证拿到最新数据。 

PureMVC(AS3)剖析:吐槽

2013-02-17 20:57 by 吴秦, 4190 阅读, 0 评论, 收藏编辑

PureMVCAS3)剖析:吐槽

写在前面

世上没有银弹——不存在适用于所有情况的框架,只有适合的框架。再者任何一个好的东西(语言、框架等)最终还取决于用的人,语言和框架本身并不能保证用户的代码清晰、解耦等,当然它只是尽可能地做到这点。所以记住我写这篇不是为了否定PureMVC,相反是为了更好的了解它、使用它

1.  吐槽一:过于强调解耦

PureMVC引入了多种设计模式、消息机制(使用观察者模式,发布/订阅模式)来解耦各个模块,它确实做到了这点,但是彻底解耦是需要代价的!

1.1.          Notification消息命名及管理复杂

PureMVC为了做到跨平台,使用Notification来实现模块间通信,而非Flash原生的EventDispatcher/Event机制。然而Notification使用字符串来定义消息,存在以下“问题”。

注:Notification并不是Event的替代物。一般情况下,Mediator给其视图组件添加Event侦听器,按常用方式处理,然后给目标Command/Mediator广播Notification

n  消息ID为字符串,虽然字符串可以做到编译时解耦,但无法做到消息强类型,这样错误将推迟到运行时才能发现。

n  消息命名,在一个大型项目中,需要一套详细的规则。相信我,否则你会吃苦头的。特别是多人参与项目中,如果没有按照一定规则命名,命名冲突可是会让你调试一阵。但不管你如何定义命名规则,【记住】为了模块间解耦,Notification发布者应该不关心谁对这个消息感兴趣(谁来处理),感兴趣者自行注册(Mediator通过listNotificationInterests注册、Command通过facade.registerCommand()注册)。例如当Proxy中用户信息改变时,不应该sendNotification通过“UpdateUserInfoVIew”“UpdateFriendListView”2个通过来分别更新用户信息、好友列表中对应用户的信息,而只是发送一个通知,如“UpdateUserInfo”,用户信息栏、好友列表都注册这个消息,然后分别处理。

n  无法知道Notification的源头。然而这点可以通过在消息体body中,增加字段标识,如:

sendNotification(ApplicationConstants.UPDATE_LEVEL_DATA, { “noticeSource”: this, “levelData”: m_levelData } );

noticeSource标识消息来源,如果您还想要知道消息传递层次,可以用数组表示,顺序插入传递者。

1.2.          强松耦合加重通信次数

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

clip_image002[4]

图:UI使用Notification修改Proxy中的数据通信过程

PureMVCUI修改Proxy的数据并返回后刷新过程:❶Mediator收到UI提交事件后,发送Notification消息给Command❸Command进行业务逻辑处理,调用Proxy接口修改数据(这里还可能涉及到与服务器通信),❺然后发消息给Mediator刷新,❻Mediator收到消息调用UI接口刷新。

因为都是消息机制,整个流程很长,而且Proxy中对数据进行操作后,发送Notification时,可能需要携带修改后的数据(可能是来自服务器的数据)。这个过程不仅通过次数多,而且带反馈数据的消息增加通信负担。另一方面要调试这个过程,我们只能在编译的时候找出一步一步的通信流程,才能跟踪调试。

2.  吐槽二:解耦增加了代码量,不方便调试

解耦的同时将使项目修改的复杂程度提高,某些解耦的办法还会增加代码量、降低执行效率。PureMVC是一个强解耦的框架,其效率本身不是很高,函数调用层次较深,而有时根本不清楚消息发到了哪里。

PureMVC为了实现解耦增加了代码量,不方便调试,但哪个MVC框架不是呢!这不是PureMVC的问题,已经有前辈编写了PureMVC模版,如FlashDevelop的模板(下载),使用模板可以减少手动编写代码量,但不能减少类的数量。

有篇文章详细介绍了PureMVC的耦合与解耦:耦合与脱耦——深入分析为什么使用pureMVC、接口或抽象基类(入口http://bbs.9ria.com/thread-161667-1-1.html

3.  吐槽三:过度使用单例模式

单例模式过于万能,属于高耦合写法。PureMVC中有4个单例ModelViewControllerFaçade我们可以通过ModelViewControllergetInstance()方法获取实例,并对他们进行操作。然而Façade是用于管理ModelViewController并对外提供接口。如果ModelViewController对外不可见,为什么要设定为单例,而不是Façade的成员变量呢?

4.  总结

上面说了一些PureMVC的缺点,不过总体来说PureMVC还算一个优秀的框架,解耦彻底、灵活性高。

PureMVC(AS3)剖析:设计模式(一)

2013-03-14 00:56 by 吴秦, 4156 阅读, 2 评论, 收藏编辑

PureMVCAS3)剖析:设计模式(一)

模式

PureMVC框架的目标很明确,即把程序分为低耦合的三层:ModelViewController。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。PureMVC框架使用多重设计模式来实现解耦彻底、灵活性。

l  单例(singleton)模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。在PureMVC实现的经典MVC元设计模式中,这三部分由三个单例类管理,分别是Model ViewControllerPureMVC中还有另外一个单例类——Façade,为子系统提供统一接口;

l  PureMVC中模块间使用观察者(Observer)模式通信,以便当一个对象的状态发生改变时,所有依赖它的对象都得到通知并更新。如Proxy中数据更新了,sendNotification通知所有相关显示的地方更新显示;

l  使用外观(Façade)模式为子系统ModelViewController接口提供一致对外的界面,定义了一组高层接口,这使得子系统更容易使用;

l  使用中介者(Mediator)模式来封装UI与系统中其他对象的交互,使得各对象不需要显示地互相引用,从而使得其耦合松散,而且可以独立地改变它们之间的交互;

l  使用代理(Proxy)模式为数据对象提供代理以控制数据对象的访问,PureMVCProxy负责操作数据模型,与远程服务信存取数据;

l  使用命令(Command)模式将请求封装为一个对象,实现“行为请求者”与“行为实现者”解耦将发出命令的责任和执行命令的责任分割开。

下面详细介绍PureMVC框架中使用的模式。

1.  单例模式

单例(singleton)模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。它有如下特点:

1)        类只能有一个实例;

2)        它必须自行创建这个实例;

3)        它必须自行向整个系统提供这个实例。

clip_image002[4]

图:单例模式类图

一般语言可以将构造函数置为private,以阻止外部实例化。然而由于AS3中的构造函数必须是public,所以不可以像其它编程语言一样,将构造函数置为private来阻止调用构造函数生成实例。PureMVC中这样实现单例类,例如View单例:

View

public class View implements IView

{

       /**

        * @throws Error Error if Singleton instance has already been constructed

        */

       public function View( )

       {

              if (instance != null) throw Error(SINGLETON_MSG);

              instance = this;

              mediatorMap = new Array();

              observerMap = new Array();  

       }

       public static function getInstance() : IView

       {

              if ( instance == null ) instance = new View( );

              return instance;

       }

       …

}

另一种通过保外类实现单例的方式,可以参考这篇文章【游戏中的背景音乐和声效】http://goo.gl/PGPLL

PureMVC中有4个类都使用了单例模式:Façade(外观模式常使用单例模式)、ModelViewController

2.  外观模式

外观(Façade)模式为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用

clip_image004[4]

图:façade模式效果

引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。外观模式特点如下:

l  外观模式为复杂子系统提供了一个简单接口,并不为子系统添加新的功能和行为【注意】

l  外观模式实现了子系统与客户之间的松耦合关系。

l  外观模式没有封装子系统的类,只是提供了简单的接口。如果应用需要,它并不限制客户使用子系统类。因此可以在系统易用性与通用性之间选择。

l  外观模式注重的是简化接口,它更多的时候是从架构的层次去看整个系统,而并非单个类的层次。

l  外观模式经常使用单例实现,但子系统们可以有多个Façade

PureMVC中,为ModelViewController类提供了外观类FaçadeFaçade统一对外提供这3者的接口,使用过程成只需要跟Façade打交道就行。

clip_image006[4]

图:façadeModelViewController

3.  观察者模式

观察者(Observer)模式(有时又被称为发布/订阅模式),定义对象间的一种一对多依赖关系,使得一个对象状态发送改变时,其相关依赖对象皆得到通知并被自动更新。这里涉及到3个角色:

l  观察者(订阅者):被通知的对象,它需要事先注册对应消息/主题。

l  通知者(发布者):发生改变的对象,当状态发生改变时通知所有依赖它的观察者更新。

l  消息(主题):消息/主题标识观察者感兴趣的内容、通知者状态改变时需要发布的内容。

为了彻底解耦,避免直接的函数调用,PureMVC使用观察者模式(发布/订阅)的形式传递消息。在PureMVCMediatorProxyCommand之间的通信,以通知形式实现松散耦合。MediatorProxyCommand都是通知者(发布者)可以调用sendNotification发送消息MediatorCommand同时也是观察者(订阅者)可以接收来自其它对象的通知

观察者模式中,维护观察者、通知者、消息/主题之间的映射关系有多种方式:

1)        由通知者维护对应的消息/主题、观察者的映射关系,并在自身状态发送改变时,通知所有的观察者;

2)        由一个管理器维护所有消息/主题、观察者之间的映射关系,当通知者发布消息时,通过管理器调用观察者通知更新。(PureMVC使用这种模式,View是管理器,管理全局的消息映射关系

clip_image008[4]

图:通知者、观察者、管理器、消息类

3.1.          发布通知

所有的通知者(发布者)都继承自Notifier类,故拥有发布通知的功能,然而Notifier是使用Façade发布通知的。

Notifier

public class Notifier implements INotifier

{

       public function sendNotification( notificationName:String, body:Object=null, type:String=null ):void

       {

              facade.sendNotification( notificationName, body, type );

       }

      

       // Local reference to the Facade Singleton

       protected var facade:IFacade = Facade.getInstance();

}

由前面介绍的外观模式可知façade保存了View的引用,View在观察者模式中充当着管理者的角色,保存着所有消息/主题、观察者的映射。当Mediator/Command/Proxy发布通知时,façade调用ViewnotifyObservers()方法,遍历保存的映射关系,从而通知所有满足条件的观察者PureMVCMediator/Command/Proxy发布通知的时序如下图所示:

clip_image010[4]

图:发布通知时序

3.2.          注册通知

观察者想接受到相应通知必须先注册,MediatorCommand分别通过以下接口注册:

l  listNotificationInterests():Array

l  registerCommand( notificationName : String, commandClassRef : Class ) : void

MediatorCommand从注册到接收通知的时序图如下:

clip_image012[4]

图:注册、接收通知时序

下篇将介绍PureMVC中的中介者模式、代理模式、命令模式。

PureMVC(AS3)剖析:设计模式(二)

2013-03-25 14:00 by 吴秦, 2893 阅读, 7 评论, 收藏编辑

PureMVCAS3)剖析:设计模式(二)

模式

上一篇中介绍了PureMVC中使用的3种设计模式:单例模式、观察者模式、外观模式。本篇将继续介绍剩下的3种设计模式:

l  使用中介者(Mediator)模式来封装UI与系统中其他对象的交互,使得各对象不需要显示地互相引用,从而使得其耦合松散,而且可以独立地改变它们之间的交互;

l  使用代理(Proxy)模式为数据对象提供代理以控制数据对象的访问,PureMVCProxy负责操作数据模型,与远程服务信存取数据;

l  使用命令(Command)模式将请求封装为一个对象,实现“行为请求者”与“行为实现者”解耦将发出命令的责任和执行命令的责任分割开。

1.  中介者模式

中介者(Mediator)模式:用一个中介对象来封装一系列对象交互。中介者使各对象不需要相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。适用性:(摘自:《设计模式:可复用面向对象软件的基础》)

l  一组对象以定义良好但是复杂的方式进行通信。产生的相互依赖关系结构混乱且难以理解。

l  一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。

l  想定制一个分布在多个类中的行为,而又不想生成太多的子类。

PureMVC中,Mediator帮助我们创建或重用已有UI组件,而UI不用知道PureMVC框架相关的东西,UI仅用于显示数据、接收用户输入。MediatorUI组件与框架的中介,它负责将来自PureMVC框架的消息转接到UI,并将UI的消息(flash事件)转发广播到PureMVC框架。这样通过Mediator解耦了UIPureMVC框架元素(ProxyMediatorCommand),而不用互相引用。

clip_image002[4]

图:中介者模式

一个Mediator只与一个UI绑定(11),Mediator构造函数参数传递与之绑定的UI。通过façaderegisterMediator方法注册Mediator,以接收PureMVC框架的通知(通过上篇介绍的外观模式,可以知道其实最终是通过View这个单例来注册的,façade只是提供接口)。

clip_image004[4]

图:MediatorUI的关系

2.  代理模式

代理(Proxy)模式:为其它的对象提供一种代理,以控制对这个对象的访问。按照使用目的来划分,代理有以下几种:(摘自:《设计模式:可复用面向对象软件的基础》)

l  远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间可以是在本机器中,也可是在另一台机器中。远程代理又叫做大使(Ambassador)。

l  虚拟(Virtual)代理:根据需要创建一个资源消耗较大的对象,使得此对象只在需要时才会被真正创建。

l  Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。

l  保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。

l  Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

l  防火墙(Firewall)代理:保护目标,不让恶意用户接近。

l  同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。

l  智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

在所有种类的代理模式中,虚拟(Virtual)代理、远程(Remote)代理、智能引用代理(Smart Reference Proxy)和保护(Protect or Access)代理是最为常见的代理模式。

PureMVC中,Proxy帮助我们以更易于重用、修改对应用程序影响最小的方式暴露数据结构、接口给应用程序。Proxy可能只是简单的管理本地数据对象,以同步方式获取或修改数据;也可能是远程服务器数据,以异步方式操作数据,服务器数据返回之后以Notification方式告诉应用程序。

总之,Proxy 集中程序的Domain Logic(域逻辑),并对外公布操作数据对象的 API。它封装了所有对数据模型的操作,不管数据是客户端还是服务器端的,对程序其他部分来说就是数据的访问是同步还是异步的。

clip_image006[4]

图:Proxy模式

3.  命令模式

命令(Command)模式:又称为行动(Action)模式或交易(Transaction)模式,命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。(摘自:《设计模式:可复用面向对象软件的基础》)

命令模式是对命令的封装,把发出命令的责任执行命令的责任分割开,委派给不同的对象。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否被执行、何时被执行,以及是怎么被执行的。

clip_image008[4]

图:PureMVC中命令执行时序

PureMVC中,命令用来检索、操作Proxy,或者与Mediator通信,或者执行其它命令(符合命令)。命令有两种:SimpleCommandMacroCommand,分别用于执行单个任务、多个任务。MacroCommand可以顺序其实多个SimpleCommand

clip_image010[4]

图:简单命令与复合命令

命令模式优点:(http://baike.baidu.com/view/1963264.htm

l  降低对象之间的耦合度。

l  新的命令可以很容易地加入到系统中。

l  可以比较容易地设计一个组合命令。

l  调用同一方法实现不同的功能

命令模式缺点:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此系统可能需要大量具体命令类,这将影响命令模式的使用。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/203544.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 数组元素的下标超出所定义的_数组元素的下标超出所定义的

    数组元素的下标超出所定义的_数组元素的下标超出所定义的问题错误信息:数组成员引用下标超出定义范围原因使用数组成员的时候,下标超出了数组最大个数。解决方法仅用于自己编写程序,所以如果是别人做好的程序,运行出现错误,你又没代码的话那就没用了。解决思路就是正确使用数组下标,不要超过数组最大成员数。下面是两种笨方法:方法一在使用数组成员的时候,检查数组的最大成员数。例如:如果真(取数组成员数(数组名)>0)确定数组有成员,之后再引用。方法二菜单的工具-系统配置-编译,勾选“是否启用快速数组访问方式”。(调试时仍然会

    2022年10月19日
  • Redis配置文件详解

    Redis配置文件详解redis是一款开源的、高性能的键-值存储(key-valuestore),和memcached类似,redis常被称作是一款key-value内存存储系统或者内存数据库,同时由于它支持丰富的数据结构,又被称为一种数据结构服务器(datastructureserver)。编译完redis,它的配置文件在源码目录下redis.conf ,将其拷贝到工作目录下即可使用,下面具体解释r

  • vector越界访问会怎么样_vector下标访问

    vector越界访问会怎么样_vector下标访问intmain(){vector<int>ivec(10);cout<<ivec[0]<<endl;cout<<ivec[100]<endl;}vector中包含三个迭代器:first迭代器指向第一个元素;finish迭代器指向最后一个有效元素的下一个位置;end_of_storage迭代器指向整个vector空间末尾的下一个位置。访问ve…

  • 代理重加密_代理重加密BBS方案

    代理重加密_代理重加密BBS方案云计算中的数据机密性风险极大地阻碍了云计算的应用,而在用户端加密的模式对于数据共享来说非常不便,用户频繁的获取和释放授权将使得用户增效据加解密工作繁重。因此代理重加密技术在云端进行数据的密文转换,减轻了用户端的负担,同时加强了云端数据的保密性。一、代理重加密代理重加密是密文间的一种密钥转换机制,是由Blaze等人在1998年的欧洲密码学年会上提出的,并由Ateniese等人在2005年的网络和分布式系统安全研讨会议和2007年的美国计算机学会计算机与通信安全会议上给出了规范的形式化定义。在代理重加密中

  • w ndows7快速关机,windows7怎么快速关机|win7系统实现快速关机的方法

    w ndows7快速关机,windows7怎么快速关机|win7系统实现快速关机的方法windows7系统怎么快速关机?现如今大家追不仅仅追求开机速度,关机速度也是大家所追求的。要不别人都下班了,你的电脑还在等待关闭是不是很不爽呢?windows7怎么快速关机?可以通过设置注册表来实现快速关机。下面小编分享win7系统实现快速关机的方法,有需要的用户可以一起来学习下。具体方法如下:1、点击【开始】-【运行】,输入“regedit”打开注册表编辑器;2、打开注册表编辑器窗口,找到H…

    2022年10月29日
  • 概率公理化定义的理解

    概率公理化定义的理解由于自己研究生方向为计算机视觉,需要用到许多概率论方面相关的知识,出来混早晚是要还滴!由于本科概率论课不太适应老师的语调,大多数课都睡过去了。。。就连最基本的概率的公理化定义,都快大学毕业了,都一直没有理解,真是囧!赶紧恶补了下概率论,感觉对公理化定义有了一点新的认识,一方面写出来加深自己的记忆,一方面分享出来,供有同样疑问的同学看看,水平有限,如有错误也在所难免,恳请大家指出,然后我进行改正

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号