0%

MVC、MVP、MVVM 架构的特点与区别

关于MVC、MVP、MVVM这几种架构方式的理解。

引言

   前人种树,后人乘凉。关于MVC、MVP、MVVM这几种架构方式的理解,前辈们写了很多的解答,我结合几篇好文,总结了以下一点点内容。

   软件的架构方式有很多种,从最开始的MVC模式,到MVP,然后到现在的MVVM,在不断的演化过程中其核心的思想就是降低各组件之间的耦合度,使得数据的流向更加的清晰明了。但并不是意味着一个比另一个高级,只是对于软件的架构方式有的不同的视角,针对不同的场景有了更多的选择方案。那么,软件架构到底是什么呢,他有什么作用呢?其实,架构就相当于人的骨架,他决定了软件开发之后所有的操作是基于一种什么样的方式进行的,因此,他对于开发是至关重要的。

   (Model-View-Controller)(Model-View-ViewModel)在概念上都是基于分层的,将表现与数据分开的设计架构,M 和 V 基本上不是问题,但将这两个整合的中间这层可就有很多的学问,另外,除了 MVC 和 MVVM 外,还有一个叫做 MVP (Model-View-Presenter)的架构,这三个的设计概念非常类似,很容易会让人傻傻分不清楚……

   我们先来看各个架构的设计原则好了。

MVC

MVC定义

   首先是 MVC,顾名思义,MVC 是将 Model、View 和 Controller 分离,让彼此的职责能够明确的分开,这样不论是改 M、 V 还是 C,都可以确保另外两层可不用做任何修改,同时这样的分层也可以加强程序的可测试性,View 和 Model 基本上是相关的,但它们并不会有直接的相依关系,而是由 Controller 去决定 Model 产生的数据,然后丢给 View 去做呈现,也就是说,Controller 是 Model 和 View 之间的协调者,View 和 Model 不能直接沟通,以确保责任的分离。

  • Model: 模型(用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法)

  • View: 视图(渲染页面)

  • Controller: 控制器(M和V之间的连接器,用于控制应用程序的流程,及页面的业务逻辑)

顺便贴一张关于前后端MVC架构的图片

前后端MVC

MVC特点

   MVC模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,能够满足其复杂性和丰富性。
   MVC模式的特点在于实现关注点分离,即应用程序中的数据模型与业务和展示逻辑解耦。在客户端web开发中,就是将模型(M-数据、操作数据)、视图(V-显示数据的HTML元素)之间实现代码分离,松散耦合,使之成为一个更容易开发、维护和测试的客户端应用程序。

  • View 传送指令到 Controller。

  • Controller 完成业务逻辑后,要求 Model 改变状态。

  • Model 将新的数据发送到 View,用户得到反馈。

MVC优缺点

优点

  • 优点是对于混乱的软件组织方式有了一个明确的组织方式,通过Control来掌控全局,同时将View展示和Model的变化分离开。

  • 耦合性低,视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码。

  • 重用性高

  • 生命周期成本低

  • MVC使开发和维护用户接口的技术含量降低

  • 可维护性高,分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。

  • 部署快

缺点

  • View和Model之间是直接进行交互的,也就是说View和Model之间是可以相互产生影响的,这样在代码中就必然会导致View和Model之间的耦合。

  • 不适合小型,中等规模的应用程序,花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。

  • 视图与控制器间过于紧密连接,视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

  • 视图对模型数据的低效率访问,依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

MVC补充

  • MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。

概念

  • MVC(Model–View–Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
  • 在MVC中,M层处理数据,业务逻辑等;V层处理界面的显示结果;C层起到桥梁的作用,来控制V层和M层通信以此来达到分离视图显示和业务逻辑层。

工作流程

  • 基本流程

    • View接受用户的交互请求(url,ajax)
    • View将请求通过路由转交给特定的Controller
    • Controller操作Model进行数据请求,Model操作DB进行对应的数据操作(增删改查CRUD)。
    • Model返回结果,Controller返回数据给View渲染。
    • View渲染完成后,将数据结果呈现给用户。
  • 图解

总结

  首先控制器接收用户的请求,并决定应该调用哪个模型来进行处理,然后模型用业务逻辑来处理用户的请求并返回数据,最后控制器用相应的视图格式化模型返回的数据,并通过表示层呈现给用户。

MVVM

MVVM定义

   再来是 MVVM,MVVM 的架构一样是 M、V 分离,但中间是以 VM (ViewModel) 来串接,这个 ViewModel 比较像是 View 的一个代理程序,它负责直接对 Model 做沟通,而 View 可以透过一些机制 (例如: Events,Databindings…) 来和 ViewModel 沟通以取得数据或将数据抛给 Model 做存取等工作,ViewModel 也可以作为和外部系统的代理程序,例如 Web Service 或是 REST Service 或是 Enterprise Services 等等,不过它和 MVC 不同的地方,就是 ViewModel 和 View 的黏合度比较高,因为 View 必须要透过 ViewModel 才可以取得 Model,而 ViewModel 又必须要处理来自 View 的通知讯息,所以虽然职责一样分明,但是却不像 MVC 那样可以扩展到整个系统组件都能用。如果 MVVM 要和 MVP 比较的话,MVVM 会比 MVP 更灵活一点。

MVVM特点

   MVVM其实是对MVP的一种改进,他将Presenter替换成了ViewModel,并通过双向的数据绑定来实现视图和数据的交互。也就是说只需要将数据和视图绑定一次之后,那么之后当数据发生改变时就会自动的在UI上刷新而不需要我们自己进行手动刷新。在MVVM中,他尽可能的会简化数据流的走向,使其变得更加简洁明了。

MVVM优缺点

优点

  • 可以使得数据流的走向更加的清晰明了,同时也简化了开发,数据和视图只需要进行一次绑定即可。

  • 低耦合,视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

  • 可重用性,可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

  • 独立开发,开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。

  • 可测试,界面向来是比较难于测试的,而现在测试可以针对ViewModel来写。

缺点

  • 目前这种架构方式的实现方式比较不完善规范

MVP

MVP定义

   接着是 MVP,MVP 一样也是职责分明,且 Model 与 View 分离的架构,但是这个 P (Presenter) 和 ViewModel 就很类似,不过就如同 Presenter (主持人) 这个字所代表的意义,所有主控 View 呈现的工作,都是由 Presenter 来做,而 View 本身只是 Presenter 所要使用的舞台而已,所以 View 原则上会相依于 Presenter,但是为了要做到关注点分离 (SoC 原则),所以在 View 和 Presenter 间都会加入一个界面 (例如: IView),然后以 IoC 的方式将 View 注射到 Presenter 中,而 Presenter 就使用接口所定义的方法去操控,而 View 就透过接口所定义的方法去呈现接口即可。但也因为受限于接口,所以 Presenter 只能依接口定义的动作去响应与处理,而不能再做更多的延伸功能,除非更改 View 的接口。

MVP特点

  • M、V、P之间双向通信。
  • View 与 Model 不通信,都通过 Presenter 传递。Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。
  • View 非常薄,不部署任何业务逻辑,称为”被动视图”(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。
  • Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,这样就可以重用。+ 不仅如此,还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试–从而不需要使用自动化的测试工具。

MVP优缺点

优点

  • 优点是可以是得整个软件分层清晰,降低耦合度。

  • 模型与视图完全分离,我们可以修改视图而不影响模型。

  • 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部。

  • 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

  • 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)。

缺点

  • 缺点是需要加入Presenter来作为桥梁协调View和Model,同时也会导致Presenter变得很臃肿。

  • 视图和Presenter的交互会过于频繁,使得他们的联系过于紧密。也就是说,一旦视图变更了,presenter也要变更。

案例总结

   以上的解释是不是看蒙圈了,OK,我又发现一篇(作者:这是你的玩具车吗)博文里面写的讲解,发现挺容易懂的,我们一起来看一下。

   这三个架构的区别在“M与V联系”的部分。针对这一部分我们来做一个对比:

Controller: 负责监听View的用户事件,得到数据后Controller做一些处理,然后渲染View。

   当然,在一些后端MVC架构里,Model也可以直接渲染View模版,但这只是不同变种的实现,这里不多做讨论。
但是随时逻辑的复杂,这样的处理遇到了很难调试的问题。由于View一定要运行在UI环境下,而且Model或者Controller和View强耦合,没有办法单独验证应用逻辑的正确性。当出了问题之后,因为各个模块是耦合在一起的,也不能快速判断究竟是哪个模块出现的问题。因此,MVP模式出现了。

Presenter: 比起Controller,Presenter会调用View层提供的接口去渲染Model。这样做有几点好处:

  1. 面向接口编程
  2. 更好的解耦
  3. 方便做单元测试

   现在P和V解耦了,P可以自己做单元测试了。软件结构划分的更加清楚,逻辑清晰并方便调试。但是这一切都来自于一个前提:View层要提供接口。当一个UI复杂起来的时候,View层需要提供的接口是很多的,这本身也是一种开发调试的成本。所以,MVVM应运而生。

ViewModel: 比起MVP中View需要自己提供API,MVVM在VM中构建一组状态数据(state data),作为View状态的抽象。然后通过双向数据绑定(data binding)使VM中的状态数据(state data)与View中的显示状态(screen state)保持一致。这样,VM中的展示逻辑只需要修改对应的状态数据,就可以控制View的状态,从而避免在View上开发大量的接口。

   那么VM有没有什么缺点?有的,当UI比较简单的时候,使用VM就会使业务逻辑变得复杂,有过分设计的嫌疑。所以VM只适合复杂UI交互的项目。

举个例子:

   我们的界面上原本没有任何东西,现在用户发出一个请求(点击按钮),界面上出现一张图片,或者一段文字。那么MVC、MVP、MVVM这三种架构都是如何处理的呢。

1
2
3
4
5
6
7
1. View获取用户请求,通知Controller。
2. Controller向后台Model发起请求
3. Model获得该请求所需要的数据,传递给Controller。
4. Controller拿到这些数据,可能做一些处理,然后拿处理好的数据渲染View。
MVC: 拿到UI节点,渲染这些数据
MVP: 通过View提供的接口渲染这些数据
MVVM: 无需操作,只要VM的数据变化,通过数据双向绑定,View直接随之变化。

   这样是不是就很容易懂了。

   最后我想提的是,MVC 的包容度比 MVVM 和 MVP 要来的高,在 MVC 的 V 层,可以再进一步的包含 MVVM 或 MVP 的实作,而 C 层也可以使用 MVP (V 是输出的资料) 来进一步切割数据的流动与输出,M 层则可以类似 MVVM 的架构,当 V (组件) 有数据的异动时,VM 即可自动侦测到并更新 Model (数据库)。当然,多大的脚就穿多大的鞋,要用什么样的架构去设计,要与当时的系统环境与需求来决定,而不是只想着要用同一种架构去做所有的系统。

   学习这些概念的作用是培养我们的思考方式,站在巨人的肩膀上,了解他们的设计理念,搞清他们为什么要这样做,万一以后碰到了一些更为复杂的情况,用现有的这些无法解决时,我们就可以顺着这样的思路,自己去进行架构设计,解决问题。

原文A

原文B

bulb