PureMVC 的得与失

PureMVC 的得与失

前段时间深入的研究了一下PureMVC。PureMVC 的文档很齐全,难能可贵的是,最重要的 Best Practice 还翻译成了中文。下面是我对 PureMVC 的一些判断:

  • PureMVC 提供的不仅仅是代码库,还包括如何完成一件事情的规范和约束。对于多人合作编写复杂的游戏逻辑而言,这些是必要的。
  • PureMVC 为了降低模块间耦合,大量使用字符串 id 来定义消息。尽管降耦合的出发点是好的,但结果却导致了非常拙劣的消息传递机制。有以下缺点:
    1. 模块间通讯太繁琐
    2. 无法定义强类型约束的接口
    3. 性能差
    PureMVC 拙劣的消息机制让网友们不堪忍受,纷纷尝试着让 PureMVC 改用 as3-signals,比如这个、那个。
    其实用字符串解耦尽管消除了编译时耦合,但并未解决人脑中的耦合,反而把原本可以用静态类型描述的接口变成了无法描述的隐式接口,是不好的。这个问题上的争议一直很多,前一两年在字符串解耦的思潮下, Ruby 、 Python 等老牌动态语言突然流行起来,这两年大家都认识到接口还是描述清楚的好,所以又弃暗投明,开始纷纷关注 Haskell 、 Scala、Go 等静态语言了。
  • 包装层太多,像是 Mediator 、 Proxy 干的事情都太少了。比如 PureMVC 的 Best Practice 上说 View 封装了细粒度的显示操作,而 Mediator 则提供粗粒度的操作。有必要吗?《Unix 编程艺术》说得很清楚,最上层是业务逻辑,最下层是正交的基本操作,中间有个胶水层。如果胶水层太厚重,最后就会导致胶水层的上方和下方再出现两个胶水层。PureMVC 正好是这个反面教材,Model 在最上层, View 在最下层,Controller/Command 是中间的胶水层,悲剧的是,胶水层的上方和下方出现了 Proxy 和 Mediator 这两个胶水层的胶水层。
  • PureMVC 的程序结构是无状态的。尽管每个具体模块内部可以有自己的状态,但模块与模块之间的通讯却使用了无法知道源头的 Notification 。PureMVC 的文档中甚至洋洋自得的把这当成优点,说是相比 flash 的 EventDispatcher ,PureMVC 监听消息时无需指定是从哪个对象发出的。然而,这样的处理方式导致让某功能模块创建多个实例变得异常困难,官方的 Loadup就绕了好大的圈子才勉强支持多实例的创建,而且还要求 Loadup 的用户为每个被加载的资源都必须定义不同的 Notification,而又必须把这个 Notification 注册为 LoadupResourceLoadedCommand 来处理。PureMVC 的架构是反面向对象的,在所有的面向对象语言中一句 new XXX 就能做到的事情,PureMVC 就不行。要用PureMVC 就必须得为这个对象生成一个唯一的名字,再注册到全局的管理器上;用户得记下这个名字,然后根据名字到全局的管理器上查找出来才能用。这不是自己抽自己脸吗?亏他还好意思把这种丑陋的 Workaround 拿出来现。

现在我觉得不光是 PureMVC ,所有的 MVC 框架恐怕都不是最佳的模块划分方式。最佳的模块划分方式应该是由具体逻辑决定的,而不是首先划分成 M、V、C 三大模块,然后再在里面划子模块。比如魔兽世界给插件提供的 lua 接口,既有获取游戏数据的,又有进行操作的,还有进行显示的,那这个接口到底是 M、V还是C?就连显示功能也不是完全开放给插件的,至少插件就无法控制游戏世界的显示。昨天跟云风讨论这个问题,他认为尽管 MVC 不是最佳的,但在一开始时搞不清需求的时候,先定义一些规范至少不是最坏的。

另外,最近一两周我的项目上有一个较深远的改变,我实现了一套 HSM(Hierarchical state machine,层次状态机 ) 框架,和同事一起把游戏中最复杂的逻辑都用 HSM 重写了一遍,感觉状态机用来描述游戏用例是很给力的。我猜测如果策划把交互流程描述清楚,项目开始之初先写状态机,那么游戏架构就可以早早确定。用这种方式确定的架构是自顶向下、由具体逻辑决定的,而不是武断划分为 MVC。这也许是确定游戏架构更好的方式吧。


转载:http://hi.baidu.com/pop_atry/item/2aa6363570743a312f0f816e

你可能感兴趣的:(PureMVC 的得与失)