MVC 和 MVVM 有什么区别?

标准 “模型视图控制器” 模式和 Microsoft 的 Model / View / ViewModel 模式之间有区别吗?

答案

MVC / MVVM 是不是一个非此即彼 / 或选择。

在 ASP.Net 和 Silverlight / WPF 开发中,这两种模式以不同的方式出现。

对于 ASP.Net,MVVM 用于在视图内双向绑定数据。这通常是客户端实现(例如,使用 Knockout.js)。另一方面,MVC 是一种在服务器端分离问题的方法。

对于 Silverlight 和 WPF,MVVM 模式更具涵盖性,并且似乎可以替代 MVC(或将软件组织成单独职责的其他模式)。这种模式经常出现的一种假设是, ViewModel只是替换了MVC的控制器(好像您可以用VM来代替C来代替首字母缩写词一样,一切都会被原谅)。

该视图模型并不一定取代单独的控制器的需求。

问题在于:要独立测试 *,尤其是在需要时可重用,则视图模型不知道显示哪个视图,更重要的是不知道其数据来自何处

* 注意:实际上,控制器从 ViewModel 中删除了需要进行单元测试的大多数逻辑。然后,VM 成为一个哑容器,几乎不需要测试。这是一件好事,因为 VM 只是设计人员和编码人员之间的桥梁,因此应保持简单。

即使在 MVVM 中,控制器通常也将包含所有处理逻辑,并决定使用哪种视图模型在哪些视图中显示哪些数据。

到目前为止,我们已经看到 ViewModel 模式的主要好处是可以从 XAML 代码背后删除代码, 从而使 XAML 编辑成为一个更加独立的任务 。我们仍然会根据需要创建控制器,以控制(无双关)应用程序的整体逻辑。

我们遵循的基本 MVCVM 准则是:

  • 视图显示某种形状的数据 。他们不知道数据来自哪里。
  • ViewModels 具有一定形状的数据和命令 ,它们不知道数据或代码来自何处或如何显示。
  • 模型保存实际数据 (各种上下文,存储或其他方法)
  • 控制器侦听并发布事件。控制器提供控制什么数据可以看到以及在何处的逻辑。控制器将命令代码提供给 ViewModel,以便 ViewModel 实际上可重用。

我们还注意到, Sculpture 代码生成框架实现了 MVVM 和类似于 Prism 的模式,并且还广泛使用了控制器来分隔所有用例逻辑。

不要以为视图模型会使控制器过时。

我已经开始撰写有关此主题的博客,并将在可能的时候添加到该博客中 。将 MVCVM 与常见的导航系统结合存在问题,因为大多数导航系统仅使用 Views 和 VM,但是我将在以后的文章中进行介绍。

使用 MVCVM 模型的另一个好处是, 在应用程序的生命周期内仅控制器对象需要存在于内存中,并且控制器主要包含代码和少量状态数据(即,很小的内存开销)。与必须保留视图模型的解决方案相比,这使应用程序占用的内存少得多,并且它对于某些类型的移动开发(例如,使用 Silverlight / Prism / MEF 的 Windows Mobile)是理想的选择。当然,这确实取决于应用程序的类型,因为您可能仍需要保留偶尔缓存的 VM 以提高响应能力。

注意:这篇文章已经过多次编辑,并且没有专门针对所提出的狭窄问题,因此我也更新了第一部分,现在也涵盖了这一部分。在下面的评论中,许多讨论仅涉及 ASP.Net,而不涉及更广泛的情况。这篇文章旨在涵盖 MVVM 在 Silverlight,WPF 和 ASP.Net 中的更广泛使用,并试图劝阻人们不要用 ViewModels 替换控制器。

我认为理解这些首字母缩略词含义的最简单方法是暂时忘记它们。取而代之的是,考虑一下它们起源的软件。实际上,可以归结为早期 Web 和桌面之间的区别。

第一个缩写 MVC 起源于网络。 (是的,以前可能曾经有过,但是 Web 才是它如何被广大 Web 开发人员所采用。)考虑一下数据库,HTML 页面和它们之间的代码。让我们对其进行细化以得出 MVC:对于 »database«,让我们假设数据库加上接口代码。对于 “HTML 页面”,我们假设 HTML 模板加上模板处理代码。对于 “之间的代码”,我们假设代码将用户的点击映射到操作,这可能会影响数据库,肯定会导致显示另一个视图。就是这样,至少出于此比较的目的。

让我们保留该 Web 东西的一个功能,而不是今天,而是十年前存在的情况,当时 JavaScript 是一种卑鄙的,令人卑鄙的烦恼,真正的程序员对此很好地避免了:HTML 页面本质上是愚蠢而被动的。浏览器是瘦客户端,或者如果可以的话,是不良客户端。浏览器中没有智能。整页重新加载规则。每次都会重新生成 »view«。

让我们记住,尽管风靡一时,但与台式机相比,这种 Web 方式仍然落后很多。桌面应用程序可以是胖客户端,也可以是富客户端。 (甚至可以将 Microsoft Word 之类的程序视为某种类型的客户端,即文档的客户端。)它们是充满智慧,对数据知识丰富的客户端。他们是有状态的。他们将正在处理的数据缓存在内存中。没有像整页重新加载这样的废话。

这种丰富的桌面方式可能就是第二个缩写 MVVM 的起源。不要被字母所迷惑,不要被 C 所迷惑。控制器仍然在那里。他们必须是。什么都不会去除。我们只添加一件事:状态性,缓存在客户端上的数据(以及用于处理该数据的智能)。该数据实际上是客户端上的缓存,现在称为 »ViewModel«。这就是允许丰富交互性的原因。就是这样。

  • MVC = 模型,控制器,视图 = 本质上是单向通信 = 交互性较差
  • MVVM = 模型,控制器,缓存,视图 = 双向通信 = 丰富的交互性

我们可以看到,借助 Flash,Silverlight 和最重要的 JavaScript,Web 已包含了 MVVM。浏览器不再可以合法地称为瘦客户端。看他们的可编程性。看他们的内存消耗。查看现代网页上的所有 Javascript 交互性。

我个人认为,通过查看具体现实中所指的内容,可以更轻松地理解该理论和首字母缩写词业务。抽象的概念很有用,尤其是在具体问题上进行演示时,这样的理解可能会绕一圈。

MVVM Model-View ViewModel与 MVC, Model-View Controller类似

控制器被替换为ViewModel 。 ViewModel 位于 UI 层下面。 ViewModel 公开了视图所需的数据和命令对象。您可以将其视为视图从其获取数据和操作的容器对象。 ViewModel 从模型中提取其数据。

Russel East在博客上详细讨论了为什么 MVVM 与 MVC 不同

一方面,MVVM 是 MVC 模式的演进,该模式使用 XAML 来处理显示。 本文概述了两者的某些方面。

Model / View / ViewModel 体系结构的主要目的似乎是在数据之上(“模型”),还有另一层非可视组件(“ViewModel”),它们更紧密地映射了数据的概念数据视图(“视图”)的概念。视图绑定到的是 ViewModel,而不是直接绑定到 Model。

Microsoft 在此处提供了 Windows 环境中 MVVM 模式的说明

这是关键部分:

在 Model-View-ViewModel 设计模式中,一个应用程序由三个常规组件组成。 在此处输入图片说明

  • 模型 :这表示您的应用程序使用的数据模型。例如,在图片共享应用中,此层可能代表设备上可用的图片集以及用于读取和写入图片库的 API。

  • 视图 :一个应用程序通常由多个页面的 UI 组成。向用户显示的每个页面都是 MVVM 术语中的一个视图。视图是用于定义和设置用户所见内容的 XAML 代码。来自模型的数据会显示给用户,这是 ViewModel 的工作,它根据应用程序的当前状态向 UI 提供此数据。例如,在图片共享应用中,视图将是向用户显示设备上的相册列表,相册中的图片的 UI,以及可能向用户显示特定图片的 UI。

  • ViewModel :ViewModel 将数据模型(或简称模型)与应用程序的 UI 或视图相关联。它包含用于管理模型中数据的逻辑,并将数据公开为 XAML UI 或视图可以绑定到的一组属性。例如,在图片共享应用中,ViewModel 将公开一个相册列表,而对于每个相册,则公开一个图片列表。 UI 不知道图片来自何处以及如何检索图片。它只是知道 ViewModel 公开的一组图片并将其显示给用户。

我认为主要区别之一是在 MVC 中,您的 V 直接读取您的 M,然后通过 C 来操作数据,而在 MVVM 中,您的 VM 充当 M 代理,并为您提供可用的功能 V.

如果我还没装满垃圾,我会惊讶的是没有人创建一个混合服务器,其中您的 VM 只是一个 M 代理,而 C 提供了所有功能。

MVC 是受控环境,而 MVVM 是反应性环境。

在受控的环境中,您应该减少代码量并使用通用的逻辑源。它应该始终存在于控制器中。然而; 在网络世界中,MVC 容易分为视图创建逻辑和视图动态逻辑。创建生活在服务器上,动态生活在客户端上。通过将 ASP.NET MVC 与 AngularJS 结合使用,您会看到很多东西,而服务器将创建一个 View 并传递一个 Model 并将其发送给客户端。然后,客户端将与 View 交互,在这种情况下,AngularJS 将作为本地控制器进入。提交模型后,会将新模型或新模型传递回服务器控制器并进行处理。 (因此,循环继续进行,使用套接字或 AJAX 等时,此处理还有很多其他转换,但是在整个体系结构上都是相同的。)

MVVM 是一种反应性环境,这意味着您通常会编写将基于某些事件激活的代码(例如触发器)。在 MVVM 蓬勃发展的 XAML 中,只需使用内置的数据绑定框架 BUT 即可轻松完成所有操作,如上所述,它可以在具有任何编程语言的任何 View 的任何系统上运行。它不是特定于 MS 的。 ViewModel 触发(通常是一个属性更改事件),并且 View 根据您创建的任何触发器对其作出反应。这可以提高技术水平,但最重要的是视图是无状态的,没有逻辑。它只是根据值更改状态。此外,ViewModels 是无状态的,逻辑很少,而 Models 是状态,其逻辑基本上为零,因为它们只应保持状态。我将其描述为应用程序状态(模型),状态转换器(ViewModel),然后是可视状态 / 交互(视图)。

在 MVC 桌面或客户端应用程序中,您应该有一个 Model,并且 Controller 应该使用该 Model。控制器将基于模型修改视图。视图通常与带有接口的控制器绑定在一起,以便控制器可以使用各种视图。在 ASP.NET 中,由于 Controller 管理模型并将模型传递给选定的视图,因此 MVC 的逻辑在服务器上稍微向后倾斜。然后,视图将根据模型填充数据,并具有自己的逻辑(通常是另一个 MVC 集,例如使用 AngularJS 完成的设置)。人们会争论不休,并将其与应用程序 MVC 混淆,然后尝试同时做这两个事情,这时维护项目最终将成为灾难。使用 MVC 时,始终将逻辑和控制放在一个位置。不要在 View 后面的代码中(或在通过 JS for web 的 View 中)编写 View 逻辑以容纳 Controller 或 Model 数据。让控制器更改视图。通过它所使用的接口创建和运行视图所需的一切只是逻辑。例如,提交用户名和密码。无论是桌面还是网页(在客户端上),只要 View 触发了 Submit 操作,Controller 都应处理提交过程。如果做得正确,您总是可以轻松地在 MVC 网站或本地应用中找到自己的出路。

我个人最喜欢 MVVM,因为它具有完全的反应性。如果 Model 更改了状态,则 ViewModel 会监听并转换该状态,仅此而已!!!然后,视图正在侦听 ViewModel 的状态更改,并且它还会根据 ViewModel 的转换进行更新。有人将其称为纯 MVVM,但实际上只有一个,我不在乎您如何争论它,而它始终是纯 MVVM,其中 View 完全不包含逻辑。

这是一个小例子:假设您想在按下按钮时插入菜单幻灯片。在 MVC 中,您的界面中将具有 MenuPressed 操作。当您单击 “菜单” 按钮,然后告诉视图基于其他接口方法(例如 SlideMenuIn)在菜单中滑动时,控制器将知道。往返是出于什么原因?如果控制器决定您不能执行或要执行其他操作,这就是原因。控制器应负责视图,而视图则不执行任何操作,除非控制器如此说。然而; 在 MVVM 中,动画的幻灯片菜单应该是内置的并且是通用的,而不是被告知要在其中滑动幻灯片,而是基于某些值。因此,它侦听 ViewModel,并且当 ViewModel 说 IsMenuActive = true 时(或者,发生动画)。现在,我要说的是另外一个要点:“真正明确”,请注意。 IsMenuActive 可能是 BAD MVVM 或 ViewModel 设计的。设计 ViewModel 时,您永远不应假定 View 完全具有任何功能,而只需传递已转换的模型状态即可。这样,如果您决定更改视图以删除菜单,而仅以另一种方式显示数据 / 选项,则 ViewModel 不在乎。那么,您将如何管理菜单?当数据有意义时,就是这样。因此,执行此操作的一种方法是为 Menu 提供选项列表(可能是内部 ViewModel 的数组)。如果该列表中有数据,则菜单会通过触发器知道打开,否则就知道会通过触发器隐藏。您只是在菜单中有数据,还是在 ViewModel 中没有。不要决定在 ViewModel 中显示 / 隐藏该数据。仅转换模型的状态。这样,视图就完全是被动的和通用的,可以在许多不同的情况下使用。

如果您还没有至少略微熟悉每种体系结构,并且由于在网络上会发现大量的不良信息而对它的学习感到非常困惑,那么所有这些都可能毫无意义。

所以... 为了正确起见,请记住一些事情。预先确定如何设计应用程序并坚持下去。

如果您执行 MVC,这很好,那么请确保 Controller 是可管理的并且完全控制 View。如果您的视图较大,请考虑向具有不同控制器的视图添加控件。只是不要将那些控制器级联为不同的控制器。维护非常令人沮丧。花一点时间,以可以作为单独组件工作的方式分别设计事物…… 并始终让 Controller 告诉模型提交或持久存储。 MVC 的理想依赖项设置是View←Controller→Model或使用 ASP.NET(不要让我开始) Model←View↔Controller→Model(其中,从 Controller 到 View 的 Model 可以相同或完全不同) ... 当然,目前唯一需要了解 View 中的 Controller 的地方主要是供端点参考,以了解将模型传递回何处。

如果您使用 MVVM,我会祝福您的良心,但是花点时间做对吧!请勿将接口用于其中之一。让您的 View 根据值决定外观。播放 “模拟视图” 数据。如果您最终拥有一个显示菜单的视图(按照示例),即使您当时不想要它,也可以选择 “好”。您认为视图正在按其应有的方式工作,并根据应有的值做出反应。只需向触发器添加更多要求,以确保在 ViewModel 处于特定转换状态时不会发生这种情况,或命令 ViewModel 清空此状态。在您的 ViewModel 中,请勿使用内部逻辑删除它,就像您要从那里确定 View 是否应该看到它一样。请记住,您不能假定 ViewModel 中没有菜单。最后,模型应该只允许您更改和最可能的存储状态。这是验证的地方,所有都会发生。例如,如果模型无法修改状态,那么它将简单地将自身标记为脏或类似状态。当 ViewModel 意识到这一点时,它将翻译脏的内容,然后 View 将意识到这一点并通过另一个触发器显示一些信息。 View 中的所有数据都可以绑定到 ViewModel,因此一切都是动态的,只有 Model 和 ViewModel 完全不知道 View 如何对绑定做出反应。实际上,模型也不知道 ViewModel。设置依赖项时,它们应该这样指向,并且仅这样指向View→ViewModel→Model (以及此处的注释... 这也可能会引起争议,但我不在乎... 不要将模型传递给除非该模型是不可变的,否则应使用 VIEW;否则,请使用适当的 ViewModel 对其进行包装。该视图不应看到模型周期。我让老鼠破解了您所看到的演示或您如何进行的演示,这是错误的。)

这是我的最后提示... 看一个设计良好但非常简单的 MVC 应用程序,并对 MVVM 应用程序执行相同的操作。一个将具有更大的控制权,而灵活性则被限制为零,而另一个将没有控制权和无限的灵活性。

受控环境非常适合从一组控制器或(单个来源)管理整个应用程序,而反应性环境却可以分解为单独的存储库,而完全不知道应用程序的其余部分在做什么。微管理与免费管理。

如果我对您还没有足够的困惑,请尝试与我联系。。。

归根结底,我们都是程序员,编码时无政府状态仍然存在。所以规则将被破坏,理论将发生变化,所有这些最终都会被猪吞噬... 但是当从事大型工作时项目和大型团队,这确实有助于达成设计模式并加以实施。有一天,它将使一开始采取的额外小步骤成为节省开支的突飞猛进。

简单差异:(受 Yaakov 的 Coursera AngularJS 课程启发)

在此处输入图片说明

MVC (模型视图控制器)

  1. 模型:模型包含数据信息。不调用或使用 Controller 和 View。包含业务逻辑和表示数据的方式。某些数据可能以某种形式显示在视图中。它还可以包含从某些来源检索数据的逻辑。
  2. 控制器:充当视图和模型之间的连接。查看调用 Controller 和 Controller 调用模型。它基本上通知模型和 / 或视图适当地更改。
  3. 视图:处理 UI 部分。与用户互动。

MVVM (模型视图视图模型)

ViewModel

  1. 它是视图状态的表示。
  2. 它保存在视图中显示的数据。
  3. 响应查看事件,也称为表示逻辑。
  4. 调用其他功能进行业务逻辑处理。
  5. 切勿直接要求视图显示任何内容。

MVVM 是Presentation Model模式的改进(值得商 de)。我说有争议,因为唯一的区别在于 WPF 如何提供进行数据绑定和命令处理的能力。

viewmodel 是用户界面元素的 “抽象” 模型。它必须允许您以非可视的方式执行命令和视图中的操作(例如,对其进行测试)。

如果您使用过 MVC,则可能有时发现创建模型对象以反映视图状态非常有用,例如,显示和隐藏某些编辑对话框等。在这种情况下,您正在使用 viewmodel。

MVVM 模式只是该实践对所有 UI 元素的概括。

而且这不是 Microsoft 模式,但要补充的是 WPF / Silverlight 数据绑定特别适合于使用此模式。但是,例如,没有什么可以阻止您在 Java 服务器界面上使用它。