PureMVC(AS3)剖析:开篇
缘起 |
自从事flash webgame开发起,3个项目都使用到了MVC模式:1个自己构建的MVC没有使用外部框架;2个使用的PureMVC框架。对PureMVC也有了一定的深度的认识,是时候来总结、吐槽下。现在网上已经流传很多关于PureMVC的资源,但是总觉得深度不够,故有了现在这个系列,我尽量带着自己的思考深入的介绍PureMVC,同时也能引起大家的思考。这里我并不是一味的说PureMVC有多好,它也有值得质疑和使用不爽的地方。
MVC思维
要了解PureMVC框架,首先得有MVC的思维方式,用MVC的思想去思考问题,分解需求、实现需求。MVC背后的核心思想是:
代码重用(code reusability)、关注点分离(separation of concerns,SoC)
MVC思维围绕这两点转,下面举个例子说明。对于一个游戏或软件来说,给人的第一感觉就是界面(视图View),它展示了一些数据等信息给用户。这些界面上的数据可以存储在视图View属性或定义的变量中,如游戏中用户信息栏中显示玩家的等级、经验、昵称:
图:玩家信息栏界面
这样数据跟视图绑定在一起,其它界面视图(玩家详细信息栏)想要等级、经验、昵称等数据需要访问玩家信息栏界面,又或者从后台重新拉取。
图:玩家详细信息界面
这里违反了“代码重用和关注点分离”思想,需要把数据独立出来保存在一个与View无关地方模型(Model),多个视图可以共用一份数据。这样代码即可重用,关注点也实现了分离, View只需要关注如何展示信息, Model只需要关注数据本身及相关逻辑。
上面达到了界面和数据分离之后,但是思考这样一个过程:用户操作了View需要更新Model,同理Model改变了需要更新View的显示,该如何去做?可能会想到用户操作View时直接调用Model接口去更新数据,这时其他共用这个Model的视图View如何同步更新又是一个问题。Model改变了数据,直接调用View接口更新显示的话,它必须要知道所有的共用这个模型Model的视图View。
这样视图View与模型Model就不能达到彻底的“代码重用和关注点分离”。MVC的指导思想就是把这个部分代码独立出来称为控制器Controller。模型和视图从此也只关心控制器,而不关心对方。他们的代码都是处理自己的事情,别人的事情全部交给控制器去办,这使得他们自己的功能也非常独立,减少了需要考虑的要素。
在这之后,三者的关系只存在简单的调用代码。那么为了能够彻底的分离和解耦,就可以将调用代码改为事件或者其他的动态形式(如发布/订阅、依赖注入等等),常用的MVC框架都实现了这样的功能。
图:MVC结构图(实线——>表示依赖;虚线---->表示事件/通知等)
l 模型(Model):“数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。(比较:观察者模式(软件设计模式))
l 视图(View):视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
l 控制器(Controller):控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变
请大家记住“MVC思维“及上面这些描述,后面还会引用这些。
PureMVC框架
PureMVC框架的目标很明确,即把程序分为低耦合的三层:Model、View和Controller。降低模块间的耦合性,各模块如何结合在一起工作对于创建易扩展,易维护的应用程序是非常重要的。
在PureMVC实现的经典MVC元设计模式中,这三部分由三个单例模式类管理,分别是Model 、View和Controller。三者合称为核心层或核心角色。PureMVC中还有另外一个单例模式类——Façade,Façade提供了与核心层通信的唯一接口,以简化开发复杂度。
图: PureMVC设计示意图(摘自官方网站)
从设计图中可以清楚看到,除了核心层、Façade之外,还有Mediator、Proxy、Command。
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的理解画的设计示意图:
图: PureMVC另种示意图