关于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

新的MOVE结构,和在项目中实际的感受的更多相关文章

  1. 在项目中使用ExtJS

    主要目录文件介绍 builds:压缩后的ExtJS代码,体积更小,更快:docs:开发文档:examples:官方演示示例:locale:多国语言资源文件:pkgs:ExtJS各部分功能的打包文件:r ...

  2. 准备在新项目中使用pgsql【资源收集】

    pgsql大象数据库 是我最近在关注的一款开源数据库,可以自由修改,没那么多限制,准备在新项目中使用 postgresql中国下载站 http://www.postgres.cn/download#s ...

  3. 【C++模版之旅】项目中一次活用C++模板(traits)的经历 -新注解

    问题与需求: 请读者先看这篇文章,[C++模版之旅]项目中一次活用C++模板(traits)的经历. 对于此篇文章提出的问题,我给出一个新的思路. talking is cheap,show me t ...

  4. Asp.net MVC 4新项目中创建area的后续操作

    Asp.net MVC 4新项目中创建area后,往往HomeController与area的HomeController路由发生混淆,需要手工设置一些地方避免mvc无法识别默认路由的状况. 无废话具 ...

  5. 创建一个doc对象时候 如果读取了一个已存在的xml对象时候 该xml对象的结构已存在doc中 当改变该doc结构时候 不需要创建新的doc对象

    创建一个doc对象时候 如果读取了一个已存在的xml对象时候 该xml对象的结构已存在doc中 当改变该doc结构时候不 需要创建新的doc对象 直接添加即可 他会同步过去

  6. JavaScript回顾一下js的基础知识,以及学习一下在项目中了解到的新知识

    学习文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions https://www.cnblogs.com ...

  7. Redis在新项目中的使用场景

    Redis在新项目中的使用场景 数据类型 使用场景 string 比如说,我想知道什么时候封锁一个Ip地址,Incrby命令(使用这个命令记录被访问的次数) Hash 存储用户的信息[id,name, ...

  8. celery 分布式异步任务框架(celery简单使用、celery多任务结构、celery定时任务、celery计划任务、celery在Django项目中使用Python脚本调用Django环境)

    一.celery简介: Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行.我们通常使用它来实现异步任务(async tas ...

  9. ES6系列之项目中常用的新特性

    ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...

随机推荐

  1. 开发一个struts2的实例

    前面一篇博客(实现struts2框架)带大家对基于mvc业务流程熟悉了一下,现在我们就用对mvc实现最好的框架struts2来开发一个应用实例.虽然现在MyEclipse8.5以上版本已经开始支持St ...

  2. CentOS(七)--Linux文件类型及目录配置

    这篇随笔将会对Linux系统的文件类型以及Linux的目录结构进行详细补充(linux中目录管理和权限非常重要,特别是在linux安装数据库类软件). 一.Linux更改文件权限的两种方式 在之前的一 ...

  3. ganymed-ssh2使用

    通过maven库获取ganymed-ssh2-262.jar,这是一个实现了ssh2协议的工具包,可以远程连接linux机器,执行命令,有些工作全靠它了 示例代码如下: <!--首先要建立连接, ...

  4. [改善Java代码]集合中的元素必须做到compareTo和equals同步

    实现了Comparable接口的元素就可以排序,

  5. Vi三种模式详解

    命令行模式 (command mode/一般模式) 任何时候,不管用户处于何种模式,只要按一下“ESC”键,即可使Vi进入命令行模式:我们在shell环境(提示符为$)下输入启动Vi命令,进入编辑器时 ...

  6. 【TOMCAT】Tomcat gzip压缩传输数据

    概述 由于我们项目的三维模型文件非常大,为了提高传输速度,在服务端对其做zip压缩处理非常有必要,能够极大的提高传输速度. 配置 首先需要修改web.xml中请求的数据文件的mime类型的mappin ...

  7. 【Android】日常开发android.jar文件中十五个重要的包概述

    简述Android项目中android.jar文件里包含较为重要的15个系统编译后的class文件 android.app:提供高层的程序模型,提供基本的运行环境android.content:包含各 ...

  8. Android之ORMLite实现数据持久化的简单使用

    Android中内置了sqlite,但是常用的开发语言java是面向对象的,而数据库是关系型的,二者之间的转化每次都很麻烦.(作为程序员,应该学会偷懒)而Java Web开发中有很多orm框架(其实我 ...

  9. 腾讯QQ群数据下载方法(7000万个qq群资料全泄漏)

    仔细读完一定能找到自己需要的东西 据新华网报道,国内知名安全漏洞监测平台乌云20日公布报告称,腾讯QQ群关系数据被泄露,网上可以轻易就能找到数据下载链接,根据这些数据,通过QQ号可以查询到备注姓名.年 ...

  10. oracle开启audit(审计)

    1.查看审计功能是否开启(本机已经开启,如果audit_sys_operations值为FALSE就是没开审计) [sql] view plaincopyprint? SQL> CONN /AS ...