新的MOVE结构,和在项目中实际的感受

关于MVC/MVP的瑕疵

MVC 和 MVP是最简单,最脍炙人口的框架结构。 有一段时间, 凡事有一定规模的代码,我都会架在上面,甚至后台程序也不例外(预留出可以注册的用户交互接口,作为后台控制器)。 但MVC/MVP这种万金油的框架结构并不是绝对完美的,一个严格遵守MVC结构的程序,他的设计粒度被上了一道枷锁。对于很多小的项目来说, 这无疑增加了开发时间和成本。
在我后来的一些小项目中,由于时间非常的紧,MVC/MVP结构变得畸形:

一种是变成MV结构,将很多控制代码放到了M模块;
另一种是项目早起严格的遵循MVC结构,但后期迭代的过程中,不得不加粗设计粒度,把各种代码简单的塞到Control模块,Control模块会变得越来越臃肿。

这两种情况,不论那种,都违反了MVC/MVP的设计初中,使代码变得难以维护。

 

饮鸩止渴的FrameWork

Cocoa, MFC, ASP.NET MVC framework, 等各个平台都提供了现有的MVC框架,这些框架在写一些小工具的时候是相当方便的。但我相信大家都应该深有体会,他们并不能帮我们解决实际问题。原因在于
1. 这些框架为了最大限度的公用性,都会有一些奇怪的行为。(说白了就是,一双谁都能穿的鞋,谁穿了都不会舒服。)
2. 也是因为这个原因,导致当我们程序规模稍微大一些后,不得不再次在这些框架上叠加我们自己的框架。(这有什么意义?)
3. 一旦我们使用了这些框架,整个程序就高度依赖当前平台,当前框架版本。(不提平台间的相互迁移植,MFC中就是把vs2003迁移到vs2008, 都要烦上一阵)

 

MOVE 另一个选择

首先声明,关于MOVE, 我并不是推荐,因为在这上面,我并没有充足的经验。我只是觉得,它是另一种选择罢了......


下面的链接,有一些关于MOVE的讨论,各种意见都有,是否喜欢只看个人了
http://www.reddit.com/r/programming/comments/vxlhj/mvc_is_dead_its_time_to_move_on/

 

move 的图片,来自作者博客。(MOVE的作者,不是我!!)。

我第一次看到这个是在12年7月份,当时只是觉得这图有意思。几天之后,手边正好有一个小项目。

(就是下面那个项目1, 一个坑爹,憋屈,槽点无限的项目, 。。。第一次遇到这样的,不吐不快啊。。。扯远了)

 

 


MOVE指的是(Model, Operation, View, Event)

Model :数据模型

和MVC的Model不同,这里只是简单的数据模型抽象
Model 只是对数据模型对象的一个封装,它包括一个Model名字,和若干属性。我一般还习惯在里面添加一些存取,转换的方法。

 

Operation : 各种操作

Operation 封装了对模型的操作。 它本身并不保存任何Model数据,只是负责对输入的Model数据进行修改、适时显示正确的视图给用户、对用户触发的事件做出响应。一个应用本身就是一个Operation 或者是一些Operation的聚合(视结构而定)。
1. 每个Operation可以有很多sub-operation.
2. 一个好的设计中,每个Operation 可以单独的运行,在一个程序中,当所有Operation结束时,程序运行结束

这里并不是说,各个Operation要在独立的线程或进程中运行。 还是那句,一切视结构而定,框架是死的,人是活的

 

View : 视图或用户交互接口

没啥可说的

 

Event : 事件

类似那些C构架的程序,由事件驱动。 (这个我很喜欢,因为我现在越来越讨厌重度OO, 开始喜欢纯C的程序了)

 

我的感觉

优点:
MOVE 的优点在于,对于小的项目来说,结构十分清晰、简单,它符合程序开发时候的思路:Model只负责基本数据结构的抽象,而操作与基本数据结构分离,放到了Operation模块; 模块之间靠事件通信。
缺点
1. 因为不存在设计绝对完美的项目,MOVE的松散结构,会将结构缺陷随项目规模放大。(减少对Model的交叉引用和规范每一条事件流是缓解这一问题的方法)
2. 由于是事件驱动,Model模块和View模块没有清晰的模块接口,而是一系列事件组成的列表。

 

 

两个项目的实践

我在3个小项目中使用了这个模式,项目规模都在10万行代码以内。其中有2个比较典型的

 

第一个项目, 使用了标准的Operation Tree

这个是MacOS的项目,由于不考虑移植,部分结构中,采用了apple建议的编程规范,所以有一些mvc的影子。

 

这里 Operation 采用标准的树形结构。 changes 由mainOperation向下一层层的分发,  而event由appInstance分发

 

appInstance是单件结构,并实现了eventCenter接口,他接受各个operation的事件。在appInstance中有mainControler方法, 返回一个实现了<mainControlerInterface>接口的实例

-(id<mainControlerInterface>)mainConter;

 

例如,operation1 要 向所有的operation发送reset事件

 

1. 它首先向appInstance的事件中心发送reset事件,参数是事件的发送者

[[[appInstance shareInstance] mainControler] reset:self];

 

2. 消息中心,将事件发回给mainOperation.

 

3. mainOperation, 向下逐层传递changes

 

项目完成后的感觉

优点:

1. 结构清晰。

2. 分工明确。 在changes传递的时候,每层operation完成不同的功能,并逐渐将事件细化。

        例如,在mainOperator中

             1. mainOperator会检查reset是否是工作线程,如果不是,会把它转换成工作线程。

             2. mainOperator会将reset转变为 clear 和 initialize 两个changes, 然后再下发给operation1 和 operation2

缺点:

1. 对有些模块。 树形结构往往会很深。 对于一些简单的事件,也要逐层下发。增加了很多没有必要的工作量,而且也让mainOperator的接口变得复杂。(这个真的很烦人!!)

 

 

第二个项目, 提取了主要Operation

上一个项目的缺点,是一个很大的败笔。于是在这个项目中,我区分除了主要的Operation. 在每个主要Operation中都添加了eventCenter. 这样对某些局部事件,减少了转发半径

 

经过上个项目的错误,在这个项目中,对主要Operation进行了区分。 每个主要Operation都提供事件转发功能。 这样, subOperation1 发送给 subOperation2的事件不必再经过全局eventCenter。

而且,每个operatin中甚至可以有自己的runLoop。

在这个项目中,因为分析操作比较复杂,要保存分析上下文。 因此,在analysis中实现了类似于COM套间的结构。 

 

 

项目完成后的感觉

优点:

解决了上一个框架设计中,树形结构过深的问题

 

缺点:

一定会有的。

这个项目还没有完全结束,更不会有迭代过程。因此缺点还没有显露出来 

以后会补充到这里

 

 

 

 

总结

我感觉MOVE在小项目中确实有优势,但不知道是否经得起长期的迭代和需求无休止的变更。

一切要时间说的算。吃一堑,长一智。是一个很好的学习过程。

 

转发请注明出处:http://www.cnblogs.com/liuyuxi/p/design_structure_move.html

 

 

欢迎和我交流

liu.yuxi.canaan@gmail.com

 

 

 

posted on 2013-09-30 18:59  Yuxi Liu  阅读(1289)  评论(2编辑  收藏  举报

导航