前言

前一阶段对MVC模式及其衍生模式做了一番比较深入的研究和实践,这篇文章也算是一个阶段性的回顾和总结。

经典MVC模式

经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。其中,View的定义比较清晰,就是用户界面。但对于Model和Controller的定义则较为模糊,以致在项目实践中对它们的职责产生了很多不同的理解。其中比较主流的有下面两种。

1、闭环党



比较传统,问题是Model和Controller职责不清,在实操时容易走形

2、 开放派



MVP的前身,问题是Controller职责太重,优点是View和Model没有了直接的关联

对MVP的一点浅见

如果我们希望View和Model脱离关联的话,那么很容易就会使得所有的职能都落到Controller头上,就如同上图所示。这样,Controller也就变成了Presenter,MVC也正式演化为MVP。所有的数据都由Presenter来驱动,所有的业务逻辑也由Presenter来实现。

MVP模式常见于Android,是谷歌官方推荐的App设计模式。从我找到的这张图上,可以非常明显地看出三者之间的关系。



Model只是一个数据通道,退化成了Repository。如果将Model扩而大之,那么就会变成下面这张图描述的场景:



Model摇身一变,成了一个数据交换中心。

MVP模式的优点是实现了View和Model的解耦,缺点是Presenter职责太重。

对MVVM的一些理解

MVVM模式现在非常流行,下面这张图描述了MVVM模式各部分的关系和职能:



MVVM模式同样实现了View和Model的解耦。不过和MVP模式不同的是,MVVM是从数据驱动的角度出发来解决这个问题的。ViewModel和View实现双向数据绑定,ViewModel的数据变化自动地反应到View上。这样,ViewModel就代表了View,成了一个Agent。ViewModel也承担一点业务逻辑,但非常有限(也有把大量业务逻辑放在ViewModel里面的做法,这个就和MVP没什么本质区别了)。所以,业务逻辑的职能就只能由Model来扛了。事实上,MVVM模式本质上是MVC模式去掉了Controller或者说是Model合并了Controller。

MVVM模式的优点是双向数据绑定带来的便利,Model完全不需要关心View。以数据为核心的视角非常新颖,并且在处理业务逻辑上也更加直观。缺点其实和MVP一样,只不过它是Model臃肿而已。

我们为什么需要MVC?

MVC、MVP、MVVM(这里把它们统称为MVC),这种模式的真正好处是什么?说实话,这个问题好思考了很久,脑海里闪过的答案总觉得似乎还差那么一点。最终,梳理出以下几点,和大家探讨:

专业分工的需要

程序员和设计师的技能是完全不同的,用户界面就应该由设计师来完成而非程序员。所以,我们需要一个不包含任何逻辑代码的View,以便由设计师来完成用户界面的创建工作。程序员则可以专心去做和逻辑、数据相关的工作。在这个层面上,不需要考虑让人糟心的Model/Controller还是Model/Presenter或者Model/ViewModel如何划分职责的问题。View的分离显然非常成功!

应对变化的需要

既然用户界面的问题已经得到了完美解决,那么,就该轮到业务逻辑和数据处理的问题了。需求总是在不断变化,程序猿对于产品狗的敌意就来自于不断地更改需求。于是,少改、好改就成了程序员的永恒目标。行之有效的套路其实也就是分层解耦而已。无论是Model/Controller还是Model/Presenter或者Model/ViewModel,不过是分层的角度和方法不同而已。

流程工艺的需要

在软件工程领域,规范提得很多,流程提得很少,工艺几乎没有人提过。但在传统的制造业和工程施工领域,最核心的就是流程和工艺。流程和工艺,是工业化生产的组织和产品品质的基础。

在软件工程上,代码风格规范就是一种工艺,瀑布式开发或者敏捷开发都是流程。如何划分Model和Controller的职责,是软件的一个设计过程,也属于工艺的范畴。三者之间如何依赖,其本质是一个流程问题。被依赖的一定是先于依赖者被生产出来。明确了职责划分和依赖关系,才能科学地编制开发计划,保证产出的代码的品质和效率。

有『套路』可循,我们做起事情来总是会简单快捷许多。

传统MVC模式存在的问题

我们知道,经典MVC模式早先的主要问题是Model和Controller的职责不明,但现在,主要问题是无法进行单元测试。既然已经知道问题在哪里,那么,我们来想办法解决问题就好了,但这之前,还需要解决几个别的问题。

业务逻辑、界面逻辑和数据逻辑傻傻分不清

从广义上讲,无论是点击按钮打开一个对话框,还是拨动一个开关切换界面样式,或者验证输入数据的合法性,都是业务逻辑,并没有什么必要分得那么细。从某种意义上,把业务逻辑分为内在的、直接的反应,和需要用户进一步操作的,状态不确定的过程,可能更加有用。前者例如分页显示的列表用户点击了下一页按钮,从而产生了刷新数据的指令;后者例如用户点击了编辑按钮,是否会修改数据,修改成什么数据在这个时候都是未知的。

三者之间如何依赖

这是一个大问题!经典的VMC模式中,View是依赖于Model的。但我个人的理解是View是需求的最直接的体现,所以View应该是先验的存在,应该是Model依赖View而不是相反。在实际的项目中,在确定原型后,设计师和负责接口的程序员会同时开始工作。同时,测试工程师也会开始编写测试用例和单元测试代码。他们的工作依据都是产品给出的原型。

等一个View编写完成后,依赖于这个View的Model就可以开工了,每一个View都会对于着一个Model和若干的接口。最后,就轮到依赖于若干Model的Controller登场了。这样做的好处是整个开发过程是由底向上、由表入里的,整体过程非常自然,而且结构简洁明了。

如何划分Model和Controller的职责

这是一个更大的问题,足以引起开发者的争吵不休,就如同什么语言最好一样。

抛开这些分歧,我们就会看到,无论是什么模式,它所需要解决的无非是业务逻辑和数据问题!所以,我认为问题的本质不是谁负责什么,而是如何分离业务逻辑和数据。

特定的用户界面需要特点的数据,有着特定的业务逻辑。这个前提之下,解耦是没有意义的。我们要求的职责分明,无非是为了更容易应对变化。那么,都有哪些变化呢?

  1. 界面样式变了,但业务逻辑和数据都没有变
  2. 界面样式和业务逻辑变了,但数据没有变
  3. 界面和数据变了,但业务逻辑没有变
  4. 界面和数据没有变,但业务逻辑变了
  5. 全都变了

界面的改变可以分为两种,一是样式改变,这种变化无关其他;另一种是元素变化,必然对应着数据的变化,需要修改接口。另外,就是业务逻辑的改变,而业务逻辑和数据并不存在必然关系。在MVC模式下,View的数据来源于Model,那么,Model的职责就是负责View和接口之间的数据交互,起一个数据通道或者说是数据引擎的作用。当数据发生变化的时候,只需要修改Model即可。

既然Model承担了数据引擎的职责,那业务逻辑就应该由Controller来承担。同时,因为不同的View之间也会存在交互,那么,也需要一共同的个中间人来进行转接和调度,由于Model和View是一对一的绑定关系,并不适合承担这个责任。所以,Controller负责业务逻辑是天然的。不过,那些和数据直接相关的事件,例如改变了一个选项后引起可用数据的变化、切换分页加载新数据之类的和具体业务没有关系的简单反应型的业务逻辑,我觉得交给Model去实现更简单和直接,并不一定要经过Controller去驱动Model。

在这种模式下,Model负责数据,Controller负责业务逻辑,整体是非常协调的。反过来看MVP和MVVM,因为回避职责的划分的问题导致了Presenter或Model的臃肿。

View和Model要不要双向数据绑定

非常有必要!传统的MVC是没有双向绑定的,这样,View上面数据的变化就必须通过Controller去修改Model。而建立双向绑定后,Controller就无需承担这个职责了,从整体上看,职责更加分明,逻辑也会更加简单。

改进的MVC模式

解决了以上四个问题,我们可以得到这样的一个新的MVC模式:



这种改进模式,相对传统的MVC模式,解决了职责不清的问题。相对于MVP和MVVM而言,没有因回避职责划分问题导致的庞大而混乱的Presenter/Model。在仅仅是View样式不同的场景下,Model是可以复用的。而使用哪个View,可以通过重载Model的构造函数来决定。事实上,即使View的元素不同造成数据不同,Model也可以利用泛型等技术手段来达到重用代码的目的。

因为View并不依赖任何人,所以,我们可以很方便地把View替换成单元测试代码(View本身是可根据场景需要相互替换的),只要骗过Model就OK。这个测试类一旦被Model构造出来,就会自动验证数据、模拟用户更新数据和发出指令。

在项目中展开的话,结构如下图:

后记

这不是结束,而是一个开始……

我理解的MVC的更多相关文章

  1. 【blade的UI设计】理解前端MVC与分层思想

    前言 最近校招要来了,很多大三的同学一定按捺不住心中的焦躁,其中有期待也有彷徨,或许更多的是些许担忧,最近在开始疯狂的复习了吧 这里小钗有几点建议给各位: ① 不要看得太重,关心则乱,太紧张反而表现不 ...

  2. HttpModule的认识与深入理解及MVC运行机制

    转自:http://kb.cnblogs.com/page/50130/ ASP.NET MVC架构与实战系列之二:理解MVC路由配置 http://www.cnblogs.com/jyan/arch ...

  3. 理解Spring MVC Model Attribute和Session Attribute

    作为一名 Java Web 应用开发者,你已经快速学习了 request(HttpServletRequest)和 session(HttpSession)作用域.在设计和构建 Java Web 应用 ...

  4. 项目开发设计模式理解之MVC模式

    项目开发设计模式之MVC模式: M model 模型层 V view 视图层 C control 控制器 MVC模式在B/S架构下使用很广泛的软件设计模式,分成三个相对独立的模块构成,model+vi ...

  5. 深入理解Spring MVC(山东数漫江湖)

    初始工程 使用Spring Boot和web,thymeleaf的starter来设置初始工程.xml配置如下: <parent>   <groupId>org.springf ...

  6. 【译】理解Spring MVC Model Attribute 和 Session Attribute

    作为一名 Java Web 应用开发者,你已经快速学习了 request(HttpServletRequest)和 session(HttpSession)作用域.在设计和构建 Java Web 应用 ...

  7. 深入理解Spring MVC

    如何让一个普通类成为Controller? 方案一:实现接口Controller 解析:handleRequest(request,response) 方案二:继承AbstractController ...

  8. 深入理解Spring MVC 思想

    目录  一.前言二.spring mvc 核心类与接口三.spring mvc 核心流程图 四.spring mvc DispatcherServlet说明 五.spring mvc 父子上下文的说明 ...

  9. 转载:深入理解Spring MVC 思想

    原文作者:赵磊 原文地址:http://elf8848.iteye.com/blog/875830 目录  一.前言二.spring mvc 核心类与接口三.spring mvc 核心流程图 四.sp ...

随机推荐

  1. ABP文档 - Mvc 控制器

    文档目录 本节内容: 简介 AbpController基类 本地化 其它 过滤 异常处理和结果包装 审计日志 验证 授权 工作单元 反伪造 模型绑定器 简介 ABP通过nuget包Abp.Web.Mv ...

  2. nodejs进阶(2)—函数模块调用

    函数调用 1. 文件内普通函数调用 创建一个js文件命名为2_callFunction.js,其中定义一个函数fun1,向返回对象输出了一段字符串“你好,我是fun1”. //------------ ...

  3. 零OCR基础6行代码实现C#验证码识别

    这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接 ...

  4. 【定有惊喜】android程序员如何做自己的API接口?php与android的良好交互(附环境搭建),让前端数据动起来~

    一.写在前面 web开发有前端和后端之分,其实android还是有前端和后端之分.android开发就相当于手机app的前端,一般都是php+android或者jsp+android开发.androi ...

  5. Python学习

    Python基础教程        网易云课堂-零基础入门学习Python

  6. BPM配置故事之案例14-数据字典与数据联动

    小明遇到了点麻烦,他昨天又收到了行政主管发来的邮件,要求把出差申请单改由H3 BPM进行,表单如下 行政主管的出差申请表 小明对表单进行了调整,设计出了一份适合在系统中使用的表单,但在"出差 ...

  7. 手把手教你做个人 app

    我们都知道,开发一个app很大程度依赖服务端:服务端提供接口数据,然后我们展示:另外,开发一个app,还需要美工协助切图.没了接口,没了美工,app似乎只能做成单机版或工具类app,真的是这样的吗?先 ...

  8. 安卓客户端a标签长按弹框提示解决办法

    昨天工作时候发现一个bug,是关于a标签的,在安卓客户端中,如果是a标签的话,长按会出现一个弹框,如图所示 是因为安卓客户端的长按触发机制,以后进行wap端开发的时候,如果用到跳转页面尽量不要用a标签 ...

  9. Java 教程整理:基础、项目全都有

    Java 在编程语言排行榜中一直位列前排,可知 Java 语言的受欢迎程度了. 网上有很多 Java 教程,无论是基础入门还是开发小项目的教程都比比皆是,可是系统的很少,对于Java 学习者来说找到系 ...

  10. Chrome 控制台不完全指南

    Chrome的开发者工具已经强大到没朋友的地步了,特别是其功能丰富界面友好的console,使用得当可以有如下功效: 更高「逼格」更快「开发调试」更强「进阶级的Frontender」 Bug无处遁形「 ...