ChatGPT解决这个技术问题 Extra ChatGPT

MVC 和 MVVM 有什么区别? [关闭]

关闭。这个问题需要更加集中。它目前不接受答案。想改进这个问题?更新问题,使其仅通过编辑此帖子专注于一个问题。 2年前关闭。改进这个问题

标准的“模型视图控制器”模式和微软的模型/视图/视图模型模式有区别吗?

请注意,虽然 MVVM 是由 Microsoft 创造的,但许多非 Microsoft 开发人员和项目已经开始采用这种模式。这条评论是由怨恨 MS 的部门带给你的。
与 MVVM 合作了很长时间,我第一次使用 MVC 令人沮丧,直到我了解到我可以使用 MVVM 中的绑定技术将 ViewModel 来回传递给浏览器。但正如 Joel 上面所说,从浏览器获取状态的唯一方法是将更改发布在一个表单(使用名称/值)对中。如果你没有很好地理解这一点。您将在 MVC 中遇到困难。只需将控制器视为视图的依赖注入器,一切就绪。
关于高级[设计模式]的这样一个被赞成的问题。我想建议在答案中使用图表。
与 MVC 方法不同,ViewModel 不是控制器。相反,它充当绑定视图和模型之间的数据的绑定器。 MVC 格式专门设计用于在模型和视图之间创建关注点分离,而具有数据绑定的 MVVM 格式专门设计用于允许视图和模型直接相互通信。 hackernoon.com/…

L
Laurel

MVC/MVVM 不是非此即彼的选择。

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

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

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

ViewModel 不一定会取代对单独控制器的需求。

问题是:要独立测试*,特别是在需要时可重用,视图模型不知道显示它的视图是什么,但更重要的是不知道它的数据来自哪里。

*注意:实际上,控制器从 ViewModel 中删除了大部分需要单元测试的逻辑。然后,VM 变成了一个只需要很少(如果有的话)测试的哑容器。这是一件好事,因为 VM 只是设计人员和编码人员之间的桥梁,所以应该保持简单。

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

从目前我们所看到的来看,ViewModel 模式的主要好处是从 XAML 代码隐藏中删除代码,从而使 XAML 编辑成为一项更加独立的任务。我们仍然在需要时创建控制器来控制(没有双关语)我们应用程序的整体逻辑。

我们遵循的基本 MVCVM 指南是:

视图显示特定形状的数据。他们不知道数据来自哪里。

ViewModels 持有特定形状的数据和命令,它们不知道数据或代码来自何处或如何显示。

模型保存实际数据(各种上下文、存储或其他方法)

控制器监听并发布事件。控制器提供了控制可以查看哪些数据以及在何处查看数据的逻辑。控制器向 ViewModel 提供命令代码,以便 ViewModel 实际上是可重用的。

我们还注意到 Sculpture code-gen framework 实现了 MVVM 和类似于 Prism 的模式,并且它还广泛使用控制器来分离所有用例逻辑。

不要假设控制器已被视图模型淘汰。

I have started a blog on this topic which I will add to as and when I can (archive only as hosting was lost)。将 MVCVM 与常见的导航系统结合起来存在问题,因为大多数导航系统只使用视图和虚拟机,但我将在以后的文章中讨论。

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

注意:这篇文章已被多次编辑,并没有专门针对所提出的狭隘问题,所以我已经更新了第一部分,现在也涵盖了。以下评论中的大部分讨论仅与 ASP.Net 相关,与更广泛的情况无关。这篇文章旨在涵盖 MVVM 在 Silverlight、WPF 和 ASP.Net 中的更广泛使用,并试图阻止人们用 ViewModels 替换控制器。


@Tomasz Zielinski:是的,但是“在哪里使用它们”不是问题(或我回答的重点)。我的观点是控制器在 MVVM 中仍然有用。
我同意。我的评论是突然的启蒙,而不是因为我不同意你的观点。
我们还使用控制器在类似向导的 UI 中控制视图的“流动”。
@贾斯汀:我看到我那句话的措辞有点模棱两可。我实际上的意思是更容易支持所有组件的单元测试,而不仅仅是改进 ViewModel 的测试(正如你所指出的那样,它实际上在 MVCVM 中并没有做那么多......这就是你想要的)。控制器的真正好处是,您实际上从 ViewModel(人们不断推动控制器逻辑)中删除了大部分测试需求,并将其放在可以测试的地方(主要是控制器和模型)。重用注释特定于该句子中的虚拟机。我已经编辑过了。
@TomaszZielinski M(MVVM)C
B
Ben Aston

我认为理解这些首字母缩略词应该意味着什么的最简单方法是暂时忘记它们。相反,想想他们所使用的软件,每一个。它真的归结为早期网络和桌面之间的区别。

随着它们在 2000 年代中期变得越来越复杂,在 1970 年代首次描述的 MVC 软件设计模式开始应用于 Web 应用程序。想想数据库、HTML 页面和介于两者之间的代码。让我们稍微改进一下以达到 MVC:对于»database«,让我们假设数据库加上接口代码。对于»HTML 页面«,我们假设 HTML 模板加上模板处理代码。对于“中间代码”,我们假设代码将用户点击映射到操作,可能会影响数据库,肯定会导致显示另一个视图。就是这样,至少出于比较的目的。

让我们保留这个 Web 东西的一个特性,而不是像今天这样,而是像十年前那样,当时 JavaScript 是一种卑鄙、卑鄙的烦恼,真正的程序员很好地避开了这一点:HTML 页面本质上是愚蠢和被动的.浏览器是一个瘦客户端,或者如果你愿意的话,一个糟糕的客户端。浏览器没有智能。整页重新加载规则。 »view« 每次都会重新生成。

让我们记住,这种网络方式尽管风靡一时,但与桌面相比却是可怕的落后。如果您愿意,桌面应用程序是胖客户端或富客户端。 (即使是像 Microsoft Word 这样的程序也可以被认为是某种客户端,一个文档客户端。)它们是充满智慧的客户端,对他们的数据充满了知识。他们是有状态的。他们将正在处理的数据缓存在内存中。没有像整页重新加载这样的废话。

而这种丰富的桌面方式可能就是第二个缩写词 MVVM 的起源。不要被字母和 C 的遗漏所迷惑。控制器仍然存在。他们需要。什么都没有被删除。我们只添加一件事:有状态,缓存在客户端的数据(以及处理该数据的智能)。该数据,本质上是客户端上的缓存,现在被称为 »ViewModel«。它允许丰富的交互性。就是这样。

MVC = 模型、控制器、视图 = 本质上是单向通信 = 交互性差

MVVM = 模型、控制器、缓存、视图 = 双向通信 = 丰富的交互性

我们可以看到,借助 Flash、Silverlight 以及——最重要的——JavaScript,网络已经接受了 MVVM。浏览器不能再被合法地称为瘦客户端。看看它们的可编程性。看看他们的内存消耗。查看现代网页上的所有 Javascript 交互性。

就个人而言,我发现这个理论和首字母缩略词业务通过查看它在具体现实中所指的内容更容易理解。抽象概念很有用,尤其是在具体问题上进行演示时,因此理解可能会绕一圈。


MVC 并非起源于网络。 Trygve Reenskaug 在 1970 年代将 MVC 引入 Smalltalk-76。
即使改成“MVC是通过Web应用程序设计普及”。我认为这是没有适当引用的猜测。
Arialdo:谢谢,我不知道 Smalltalk-76。 (当时和其他玩具一起玩。:) 笑话不谈,有趣的是其中一些概念有多古老。 - @Dan,我写的是:“[MVC] 可能在 [web] 之前就已经存在,但 web 是它在广大 web 开发人员中普及的方式。”我仍然认为这是正确的。我没有引用它,但是我觉得我不需要引用它,因为 MVC 的大规模普及是我在过去十年开始作为 Web 开发人员时的个人经历的一部分。 Apache Struts 那时很流行,有很多用于 MVC 的 bean。
MVC 不是“本质上单向通信”,因为浏览器总是发出 Gets 和 Posts。 Gets 和 Posts 都可以更改查询字符串中的字段值。这为浏览器提供了充足的机会将信息发送回控制器。 MVC 建立在 HTTP 1.0 之上,始终牢记两种通信方式。
谢谢卢米。这对我来说比其他答案更有意义。这是对的吗?我不知道。但从我的角度来看,它至少是连贯的。
J
Just a learner

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

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

Russel East 写了一篇博客来详细讨论Why is MVVM is different from MVC


“将控制器替换为视图模型”这句话是不正确的。在 MVVM 中,控制器的作用是数据绑定(或者如果您使用它,则按约定绑定)。
MVVM 仅在使用 WPF 的双向数据绑定时才有意义。否则 MVC/MVP 等就足够了。
@DaniCE:乔什·史密斯:If you put ten software architects into a room and have them discuss what the Model-View-Controller pattern is, you will end up with twelve different opinions. …
@OmShankar 第 11 个不是你自己。共有 10 个人,共有 12 条意见。这句格言的意思是暗示这些模式的定义是如此开放,以至于至少有两个人会感到困惑,以至于有不止一种意见。
@DaniCE嗯,这实际上是WPF数据绑定的重点,微软发明了MVVM,可以完全绕过控制器,(声称“控制器正在被视图模型替换”这句话是不正确的,因为有幕后的控制器,基本上就像声称声明“更高级别的语言用更易读的机器代码代替神秘机器代码的使用”是不正确的,因为在幕后机器语言仍在使用......)
s
sll

一方面,MVVM 是 MVC 模式的发展,它使用 XAML 来处理显示。 This article 概述了两者的一些方面。

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


我认为您引用的段落很好地总结了恕我直言。 ViewModel 的一个方面是它是视图模型的扁平/更改版本。许多其他 MV* 模式与真实模型绑定。
“许多其他 MV* 模式再次绑定了真实模型”?真的吗?我认为视图总是应该绑定到 MVC 中的控制器,无论如何。
Nocturne:在经典的 MVC 中,View 与控制器没有太大关系,它主要绑定到 Model。把它想象成一个机器人——模型代表机器人关节的位置,视图是一个液晶显示器,你可以在上面看到机器人,控制器是例如键盘。在这样的设置中,View 取决于 Model,即机器人的空间位置,您在显示器上看到的就是 Model 的直接表示。
@Nocturne 丹尼尔似乎说的是,虽然正式所有 MV* 都应该使用单独的 VM,但许多开发人员只是忽略它,并通过实际模型,事实上,例如 MVC 的规范中没有任何内容不允许它,但是在 MVVM 之一虚拟机必须负责模型和视图之间的转换
我会这样说:模型是数据库模式的壁橱。运行查询时,它可以将数据投影到模型层的强类型中。 viewmodel 是事物的集合,包括模型对象,但可以并且确实保持与数据相关的视图状态。控制器只是视图模型和视图之间的交通警察,当然视图只关心视图状态。
r
ruffin

Microsoft 提供了 an explanation of the MVVM Pattern in the Windows environment here

这是一个关键部分:

在 Model-View-ViewModel 设计模式中,一个应用程序由三个通用组件组成。模型:这表示您的应用程序使用的数据模型。例如,在图片共享应用程序中,该层可能表示设备上可用的图片集以及用于读取和写入图片库的 API。视图:一个应用程序通常由多个 UI 页面组成。向用户显示的每个页面都是 MVVM 术语中的视图。视图是用于定义和设置用户所见内容的 XAML 代码。模型中的数据显示给用户,ViewModel 的工作是根据应用程序的当前状态向 UI 提供这些数据。例如,在图片共享应用程序中,视图将是向用户显示设备上的相册列表、相册中的图片以及向用户显示特定图片的另一个 UI。 ViewModel:ViewModel 将数据模型或简称模型与应用程序的 UI 或视图联系起来。它包含用于管理来自模型的数据的逻辑,并将数据作为一组属性公开,XAML UI 或视图可以绑定到这些属性。例如,在图片共享应用程序中,ViewModel 会公开一个相册列表,并为每个相册公开一个图片列表。 UI 不知道图片的来源和检索方式。它只知道 ViewModel 公开的一组图片并将它们显示给用户。


请注意,虽然引用的文章适用于使用 Microsoft Stack(特别是 Windows Phone)和 XAML 的开发,但并非必须如此。
这个答案突出了名称“MVVM”的问题——它应该是“VVMM”或“MVMV”——MV-VM 的关系完全错误!
R
Rap

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

如果我没有满是垃圾,我很惊讶没有人创建混合,您的 VM 只是一个 M 代理,而 C 提供所有功能。


+1。我认为这个词是正确的。但是关于创建混合 M-MProxy-VC 是不是太多的分离?我认为使用 MVC 就足够了,而 M 是一个完全支持绑定的模型。 ;)
+1。正如我上面评论的,我认为 MVC 用于构建整个(Web)应用程序,而 MVVM 用于 MVC 的 View 组件内部。
@ktutnik:模型通常位于服务器上,而 ViewModel 位于客户端上。所以 HTML 直接绑定到服务端 Model 是不可行的。因此,我们需要 ModelView 作为本地的、未保存的工作数据集,使用例如 AJAX/JSON 从模型中提取。
视图确实“读取”了模型数据,因为它已经被控制器放在那里。我喜欢将其称为控制器的“数据注入”,因为它实际上是负责的控制器。所有视图都在我脑海中渲染和触发事件。
我很抱歉,但不同意 MVVM 的解释。 ViewModel 不知道 View 或 View 的外观或响应方式,Model 同样不知道 ViewModel。事实上,一个视图甚至不应该知道一个模型,只是一个视图模型。 Model 应该代表数据和应用程序状态,ViewModel 应该将状态转换为 UI 支持的数据(我现在推荐所有原语),并且 View 应该对 ViewModels 的转换做出反应。数据通常是相同的,但仍应通过 ViewModel 包装和重新交付,并且不存在控制器。
M
Michael Puckett II

MVC 是受控环境,MVVM 是反应式环境。

在受控环境中,您应该拥有更少的代码和通用的逻辑源;它应该始终存在于控制器中。然而;在 Web 世界中,MVC 很容易分为视图创建逻辑和视图动态逻辑。创作存在于服务器上,动态存在于客户端。您可以在 ASP.NET MVC 与 AngularJS 的结合中看到很多,而服务器将创建一个视图并传入一个模型并将其发送到客户端。然后客户端将与视图交互,在这种情况下,AngularJS 会作为本地控制器介入。提交后,模型或新模型将传回服务器控制器并进行处理。 (因此循环继续,并且在使用套接字或 AJAX 等时,这种处理有很多其他的翻译,但总体而言,架构是相同的。)

MVVM 是一种反应式环境,这意味着您通常编写将基于某些事件激活的代码(例如触发器)。在 MVVM 蓬勃发展的 XAML 中,这一切都可以通过内置的数据绑定框架轻松完成,但如前所述,这将在任何视图中使用任何编程语言的任何系统上工作。它不是特定于 MS 的。 ViewModel 触发(通常是属性更改事件),View 根据您创建的任何触发器对其做出反应。这可能是技术性的,但底线是视图是无状态的并且没有逻辑。它只是根据值更改状态。此外,ViewModel 是无状态的,逻辑很少,而模型是具有本质上零逻辑的状态,因为它们应该只维护状态。我将其描述为应用程序状态(模型)、状态转换器(视图模型),然后是视觉状态/交互(视图)。

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

MVVM 是我个人最喜欢的,因为它完全是反应式的。如果模型更改状态,ViewModel 会监听并转换该状态,仅此而已!!!然后 View 会监听 ViewModel 的状态变化,它还会根据 ViewModel 的转换进行更新。有些人称它为纯 MVVM,但实际上只有一个,我不在乎你如何争论它,它始终是纯 MVVM,其中视图绝对不包含任何逻辑。

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

如果您还没有至少稍微熟悉每个架构的架构并且学习它可能会非常混乱,因为您会在网上找到很多糟糕的信息,那么所有这些可能完全没有意义。

所以...要记住这一点,要记住的事情。预先决定如何设计您的应用程序并坚持下去。

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

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

这是我的最后一个提示... 查看一个设计良好但非常简单的 MVC 应用程序,并为 MVVM 应用程序做同样的事情。一个人将拥有更多的控制权,但灵活性有限,而另一个人将没有控制权和无限的灵活性。

受控环境有利于从一组控制器或(单个源)管理整个应用程序,而反应式环境可以分解为单独的存储库,完全不知道应用程序的其余部分在做什么。微观管理与自由管理。

如果我还没有让您感到困惑,请尝试与我联系...我不介意通过插图和示例详细了解这一点。

归根结底,我们都是程序员,并且在编码时存在着无政府状态......所以规则会被打破,理论会改变,所有这一切最终都会被洗白......但是当在大型工作时在项目和大型团队中,就设计模式达成一致并实施它确实很有帮助。有朝一日,它会使一开始采取的额外小步骤在以后成为突飞猛进的储蓄。


惊人的详细和准确的答案!对我来说一清二楚。 :-)
“学习它可能会非常混乱,因为你会在网上找到很多不好的信息。”是的。作为一个似乎对这些设计模式有很多经验的人,你知道有什么好的教程/指南吗?
老实说,我的 MVVM 知识已经经历了多年或反复试验,并根据团队的努力以各种方式使用/完成它。我最近(2 年前)能够将自己的经验总结成一个游戏计划,并带领一个团队开始完成这项工作,我们非常成功。就是说,我不能指点你到任何一个地方并道歉。我可以说你是对的,因为各种意见很令人困惑,但是,IMO,对于 MVVM,它应该尽可能通用。使 ViewModel 能够允许视图严格绑定和处理数据,但对于任何视图......
换句话说,永远不要让 ViewModel 假设 View 会以任何方式看起来或行动。对我来说,ViewModel 最好像 API 一样使用,但要进行严格的通信。遵循游戏计划进行绑定、编辑、命令等。如果视图需要额外的逻辑来以特定方式运行,这与应用程序或数据(例如动画或下拉框..)无关,那么该逻辑不知何故属于某个视图层。再说一次,有很多意见,这只是我的,但我在这里有很强的背景和迄今为止的良好记录。
我有示例应用程序,我不介意分享,或者不介意设置一个简单的节目,如果需要或好奇的话,可以告诉你或其他任何人。
P
Pritam Banerjee

简单的区别:(受 Yaakov 的 Coursera AngularJS 课程启发)

https://i.stack.imgur.com/zoL2x.png

MVC(模型视图控制器)

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

MVVM(模型视图视图模型)

视图模型:

它是视图状态的表示。它保存视图中显示的数据。响应查看事件,也就是表示逻辑。调用其他功能进行业务逻辑处理。永远不要直接要求视图显示任何内容。


R
Ray Jasson

对于不太熟悉架构模式主题的人来说,其他答案可能不容易理解。对应用程序架构不熟悉的人可能想知道它的选择如何在实践中影响她的应用程序以及社区中的所有大惊小怪。

为了阐明上述内容,我编写了这个涉及 MVVM、MVP 和 MVC 的剧本。故事从用户点击电影搜索应用程序中的“查找”按钮开始……:

用户:点击……

观点:那是谁? [MVVM|MVP|MVC]

用户:我刚刚点击了搜索按钮……

视图:好的,等一下……。 [MVVM|MVP|MVC]

(视图调用 ViewModel|Presenter|Controller ...) [MVVM|MVP|MVC]

View:嘿 ViewModel|Presenter|Controller,一个用户刚刚点击了搜索按钮,我该怎么办? [MVVM|MVP|MVC]

ViewModel|Presenter|Controller:嗨,View,那个页面上有搜索词吗? [MVVM|MVP|MVC]

观点:是的,……在这里……“钢琴” [MVVM|MVP|MVC]

—— 这是 MVVM 和 MVP|MVC 最重要的区别 ——

Presenter|Controller:谢谢View,...同时我正在查找Model上的搜索词,请给他/她显示一个进度条[MVP|MVC]

(Presenter|Controller 正在调用模型……) [MVP|MVC]

ViewModel:谢谢,我会在 Model 上查找搜索词,但不会直接更新您。相反,如果有任何结果,我将触发事件到 searchResultsListObservable。所以你最好注意这一点。 [MVVM]

(在观察 searchResultsListObservable 中的任何触发器时,View 认为它应该向用户显示一些进度条,因为 ViewModel 不会与它对话)

——————————————————————————————

ViewModel|Presenter|Controller: Hey Model, 你有匹配这个搜索词吗?: “piano” [MVVM|MVP|MVC]

模型:嘿 ViewModel|Presenter|Controller,让我检查一下…… [MVVM|MVP|MVC]

(模型正在查询电影数据库……) [MVVM|MVP|MVC]

( 过了一会儿 … )

————这就是MVVM、MVP和MVC的分歧点——————

模型:我为你找到了一个列表,ViewModel|Presenter,这里是 JSON “[{“name”:”Piano Teacher”,”year”:2001},{“name”:”Piano”,”year”: 1993}]” [MVVM|MVP]

模型:有一些可用的结果,控制器。我在我的实例中创建了一个字段变量并用结果填充它。它的名字是“searchResultsList” [MVC]

(Presenter|Controller 感谢 Model 并返回 View)[MVP|MVC]

主持人:感谢您的等待查看,我为您找到了匹配结果列表,并将它们排列成一个像样的格式:[“Piano Teacher 2001”,”Piano 1993”]。也请现在隐藏进度条[MVP]

控制器:感谢您等待 View,我已经向 Model 询问了您的搜索查询。它说它找到了一个匹配结果列表并将它们存储在其实例内名为“searchResultsList”的变量中。你可以从那里得到它。也请现在隐藏进度条[MVC]

ViewModel:在 searchResultsListObservable 上的任何观察者都会被通知有这个新列表的格式:[“Piano Teacher 2001”,”Piano 1993”]。[MVVM]

观点:非常感谢Presenter [MVP]

视图:谢谢“控制器”[MVC](现在视图在质疑自己:我应该如何将我从模型中获得的结果呈现给用户?电影的制作年份应该排在第一位还是最后一个……?)

视图:哦,searchResultsListObservable 里面有一个新的触发器……,很好,有一个像样的列表,现在我只需在列表中显示它。既然我有结果,我也应该隐藏进度条。 [MVVM]

如果您有兴趣,我写了一系列文章here,通过实现一个电影搜索 Android 应用程序来比较 MVVM、MVP 和 MVC。


在这里的所有风味文本下都有一个很好的答案......通过一些格式和组件之间的闲聊,这可能是这个页面上最好的一个。
很好的解释并强调了 MVC 和 MVVM 之间的潜在区别
到目前为止我找到的最好的解释!
w
wekempf

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


在 2009 年,这个答案可能是一个很好的答案,但今天,甚至 MSFT 的 HTML Helper 控件都允许使用臭名昭著的“For”帮助器进行绑定,因此没有任何争议。 Knockout 是关于客户端的数据绑定。
我在 2009 年说过这一点,因为社区中有太多人接受了这个答案。我说这值得商榷,因为 MVVM 和 Presentation Model 确实是同一个模式,但名称不同。由于 WPF 中的流行,它在今天的其他框架中通常被称为 MVVM,但任何一个名称都是准确的。
D
DaniCE

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

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

MVVM 模式只是将该实践推广到所有 UI 元素。

而且它不是 Microsoft 模式,附加的是 WPF / Silverlight 数据绑定特别适合使用这种模式。但是,例如,没有什么能阻止您将它与 java 服务器端一起使用。


C
Cheng

令我惊讶的是,这是一个投票率很高的答案,却没有提及 MVVM 的起源MVVM 是 Microsoft 社区中使用的一个流行术语,它起源来自 Martin Fowler 的 Presentation Model。因此,要了解该模式的动机以及与其他模式的不同之处,首先要阅读有关该模式的原始文章。


哇...所以 MVC 和 MVVM 都来自 SmallTalk?他们显然领先于他们的时代......
实际上,说它起源于 Martin Fowler 的 Presentation Model 是不准确的。很难确定哪个先出现,但两种模式(允许它们实际上是相同的模式)是独立且大致同时到达的。
C
Community

使用 MVC 将强类型视图模型注入视图

控制器负责更新 ViewModel 并将其注入到 View 中。 (用于获取请求) ViewModel 是 DataContext 和视图状态的容器,例如最后选择的项目等。模型包含 DB 实体并且非常接近它执行查询和过滤的 DB Schema。 (我喜欢 EF 和 LINQ)模型还应该考虑存储库和/或将结果投影到强类型(EF 有一个很好的方法... EF.Database.Select(querystring, parms) 用于直接 ADO 访问以注入查询和取回强类型。这解决了 EF 是慢的参数。EF 不是慢的!ViewModel 获取数据并执行业务规则和验证回发的控制器将调用 ViewModel Post 方法并等待结果。控制器将注入新更新的视图模型到视图。视图仅使用强类型绑定。视图仅呈现数据,并将事件发送回控制器。(参见下面的示例)MVC 拦截入站请求并将其路由到具有强数据的适当控制器类型

在这个模型中,不再有与请求或响应对象的 HTTP 级别联系,因为 MSFT 的 MVC 机器对我们隐藏了它。

为澄清上述第 6 项(应要求)...

假设一个 ViewModel 是这样的:

public class myViewModel{
     public string SelectedValue {get;set;}
public void Post(){
    //due to MVC model binding the SelectedValue string above will be set by MVC model binding on post back.
    //this allows you to do something with it.
    DoSomeThingWith(SelectedValue);
    SelectedValue = "Thanks for update!";
 }
}

帖子的控制器方法将如下所示(见下文),请注意 mvm 的实例是由 MVC 绑定机制自动实例化的。结果,您永远不必下拉到查询字符串层!这是 MVC 根据查询字符串为您实例化 ViewModel!

[HTTPPOST]   
public ActionResult MyPostBackMethod (myViewModel mvm){
         if (ModelState.IsValid)
        {
               // Immediately call the only method needed in VM...
               mvm.Post()
        }
      return View(mvm);
}

请注意,为了使上述操作方法按您的预期工作,您必须定义一个空 CTOR 来初始化帖子中未返回的内容。回发还必须回发那些更改的名称/值对。如果缺少名称/值对,MVC 绑定引擎会做正确的事情,这根本就什么都不是!如果发生这种情况,您可能会发现自己说“我正在丢失回发数据”......

这种模式的优点是 ViewModel 完成了与模型/业务逻辑接口的所有“杂乱”工作,控制器只是某种路由器。这是 SOC 在行动。


你能澄清第6条吗?我意识到您仅涵盖 ASP.Net,但它似乎向 ViewModel 添加了不需要的依赖项。 (例如,了解数据来自/去往何处)。一个代码(伪代码?)示例可以很好地阐明这个答案并显示哪些部分是服务器端的,哪些是客户端的。
e
eglasius

MVVM 将视图模型添加到组合中。这很重要,因为它允许您使用 WPF 的大量绑定方法,而无需将所有 UI 特定部分放入常规模型中。

我可能是错的,但我不确定 MVVM 是否真的强制控制器进入混合状态。我发现这个概念更符合:http://martinfowler.com/eaaDev/PresentationModel.html。我认为人们选择将它与 MVC 结合起来,而不是它内置在模式中。


严格来说,MVVM 是表示模型,尽管 MVVM 正在成为 WPF 特定模式实现的首选名称。
同意。 MVC 中的视图模型“是”视图的状态机。它包含数据上下文并跟踪所有选定的项目信息,并且可以包含使用 IValidatableObject 接口的所有验证逻辑。 ViewModel 在模型层与数据库接口,可以使用强类型模型。 WPF 中的 MVVM 是 MVC 的控制器。但是 MVC 的控制器要干净得多,它是必不可少的路由处理程序。
s
se_thoughts

据我所知,MVVM 映射到 MVC 的 MV——这意味着在传统的 MVC 模式中,V 不直接与 M 通信。在 MVC 的第二个版本中,M 和 V 之间存在直接链接。MVVM似乎接受了与 M 和 V 通信相关的所有任务,并将其与 C 解耦。实际上,MVVM 中仍然存在更大范围的应用程序工作流(或使用场景的实现)。这就是控制器的作用。通过从控制器中移除这些较低级别的方面,它们更干净,并且更容易修改应用程序的使用场景和业务逻辑,也使控制器更具可重用性。


恕我直言,我认为“使控制器更可重用”的说法过于宽泛,对于一般的 ASP.Net “控制器”(即不是业务逻辑层)来说适得其反,因为这些控制器通常包含应用程序的应用程序部分-具体的。需要可重用的是视图、模型、视图模型和业务逻辑。我本来认为将业务逻辑模块视为服务提供者而不是控制器会是更好的选择。
但是您说的是 Asp.net 中的“ViewModel”,而不是 MVVM 设计模式。两种不同的东西。
S
ScottyBlades

MVVM

视图➡视图模型➡模型

该视图具有对 ViewModel 的引用,但反之则不然。

ViewModel 具有对 Model 的引用,但反之则不然。

视图没有参考模型,反之亦然。

如果您使用的是控制器,它可以引用 Views 和 ViewModels,尽管控制器并不总是必要的,如 SwiftUI 中所示。数据绑定:我们为 ViewModel 属性创建监听器,以便数据可以通过视图模型从视图流向模型。虽然引用是一种方式:View ➡ ViewModel ➡ Model,但数据需要流动:View ↔ ViewModel ↔ Model。通过读取它自己的属性,它清楚视图如何从模型中获取数据。数据绑定是如何检测视图中的事件并将它们反馈给模型。

class CustomView: UIView {
  var viewModel = MyViewModel {
    didSet {
      self.color = viewModel.viewColor
    }
  }

  convenience init(viewModel: MyViewModel) {
    self.viewModel = viewModel
  }
}


struct MyViewModel {
   var viewColor: UIColor {
      didSet {
         colorChanged?() // This is where the binding magic happens.
      }
   }
   
   var colorChanged: ((UIColor) -> Void)?
}


class MyViewController: UIViewController {

   let myViewModel = MyViewModel(viewColor: .green)
   let customView: CustomView!

   override func viewDidLoad() {
      super.viewDidLoad()

      // This is where the binder is assigned.
      myViewModel.colorChanged = { [weak self] color in 
        print("wow the color changed")
      }
      customView = CustomView(viewModel: myViewModel)
      self.view = customView
   }
}

设置差异

业务逻辑保存在 MVC 的控制器和 MVVM 的 ViewModel 中。事件直接从视图传递到 MVC 中的控制器,而事件从视图传递到 ViewModel 到 MVVM 的控制器(如果有的话)。

共同特征

MVVM 和 MVC 都不允许 View 直接向 Model/s 发送消息。两者都有模型。两者都有意见。

MVVM 的优点

因为 ViewModel 包含业务逻辑,所以它们是更小的具体对象,使它们易于单元测试。另一方面,在 MVC 中,业务逻辑在 ViewController 中。如果不同时测试所有方法和侦听器,你怎么能相信视图控制器的单元测试是全面安全的?你不能完全相信单元测试的结果。在 MVVM 中,由于业务逻辑从 Controller 中抽取到原子 ViewModel 单元中,因此 ViewController 的大小会缩小,这使得 ViewController 代码更加清晰。

MVC的优点

在控制器中提供业务逻辑减少了对分支的需求,因此语句更有可能在缓存上运行,这比将业务逻辑封装到 ViewModel 中性能更高。在一个地方提供业务逻辑可以加速不需要测试的简单应用程序的开发过程。我不知道什么时候不需要测试。在 ViewController 中提供业务逻辑对于新开发人员来说更容易考虑。


最好的解释
N
Nishu Tayal

嗯,通常 MVC 用于 Web 开发,而 MVVM 在 WPF/Silverlight 开发中最流行。但是,有时 Web 架构可能会混合使用 MVC 和 MVVM。

例如:您可能会使用 knockout.js,在这种情况下,您将在客户端拥有 MVVM。而且你的 MVC 的服务器端也可以改变。在复杂的应用程序中,没有人使用纯模型。将 ViewModel 用作 MVC 的“模型”可能有意义,而您的真实模型基本上将成为该 VM 的一部分。这为您提供了一个额外的抽象层。


什么“Web 开发”术语“MVC”只不过是关注点分离,而不是 Web 之前的真正 MVC。
d
daneejela

简而言之——在 MVC 中,控制器知道(控制)视图,而在 MVVM 中,ViewModel 不知道谁在使用它。 ViewModel 将其可观察的属性和操作公开给任何可能对使用它感兴趣的人。这个事实使测试更容易,因为 ViewModel 中没有对 UI 的引用。


I
Ini

在 MVVM 中,Controller 不会被 ViewModel 取代,因为 ViewModel 具有与 Controller 完全不同的功能。你仍然需要一个控制器,因为没有控制器你的模型、视图模型和视图将不会做很多事情......在 MVVM 中你也有一个控制器,MVVM 的名称只是误导。

在我看来,MVVMC 是正确的名称。

如您所见,ViewModel 只是 MVC 模式的一个补充。它将转换逻辑(例如将对象转换为字符串)从 Controller 移动到 ViewModel。


d
der Martin

MVMC,或者可能是 MVC+,对于企业以及快速应用程序开发来说似乎是一种可行的方法。虽然将 UI 与业务和交互逻辑分开是很好的,但“纯”MVVM 模式和大多数可用示例在单一视图上效果最好。

不确定您的设计,但是我的大多数应用程序都包含页面和几个(可重用)视图,因此 ViewModel 确实需要在某种程度上进行交互。使用页面作为控制器将完全破坏 MVVM 的目的,因此不使用“VM-C”方法来处理底层逻辑可能会导致......好吧......随着应用程序的成熟,具有挑战性的构造。即使在 VB-6 中,我们大多数人也可能停止将业务逻辑编码到 Button 事件中并开始将命令“中继”到控制器,对吧?我最近查看了许多关于该主题的新兴框架;我最喜欢的显然是 Magellan(在 codeplex)方法。快乐编码!

http://en.wikipedia.org/wiki/Model_View_ViewModel#References


R
Rahul

模型-视图-控制器(通常称为 MVC)是一种软件设计模式,通常用于开发用户界面,将相关的程序逻辑划分为三个相互关联的元素。这样做是为了将信息的内部表示与信息呈现给用户和被用户接受的方式分开。遵循 MVC 架构模式将这些主要组件解耦,从而允许代码重用和并行开发。

传统上用于桌面图形用户界面 (GUI),这种模式在设计 Web 应用程序时变得很流行。 JavaScript、Python、Ruby、PHP、Java 和 C# 等流行的编程语言具有开箱即用的用于 Web 应用程序开发的 MVC 框架。

模型

模式的中心组件。它是应用程序的动态数据结构,独立于用户界面。它直接管理应用程序的数据、逻辑和规则。

看法

信息的任何表示形式,例如图表、图表或表格。相同信息的多个视图是可能的,例如用于管理的条形图和用于会计师的表格视图。

控制器

接受输入并将其转换为模型或视图的命令。

除了将应用程序划分为这些组件之外,模型-视图-控制器设计还定义了它们之间的交互。

模型负责管理应用程序的数据。它接收来自控制器的用户输入。

视图意味着以特定格式呈现模型。

https://i.stack.imgur.com/munxk.png

模型-视图-视图模型 (MVVM) 是一种软件架构模式。

MVVM 促进了图形用户界面的开发——无论是通过标记语言还是 GUI 代码——与业务逻辑或后端逻辑(数据模型)的开发分离。 MVVM 的视图模型是一个值转换器,这意味着视图模型负责以易于管理和呈现对象的方式从模型中公开(转换)数据对象。在这方面,视图模型比视图更像模型,并且处理大部分(如果不是全部)视图的显示逻辑。视图模型可以实现中介者模式,围绕视图支持的用例集组织对后端逻辑的访问。

MVVM 是 Martin Fowler 的演示模型设计模式的一种变体。 MVVM 以相同的方式抽象视图的状态和行为,但 Presentation Model 以不依赖于特定用户界面平台的方式抽象视图(创建视图模型)。

MVVM 由 Microsoft 架构师 Ken Cooper 和 Ted Peters 发明,专门用于简化用户界面的事件驱动编程。该模式被纳入 Windows Presentation Foundation (WPF)(Microsoft 的 .NET 图形系统)和 Silverlight(WPF 的 Internet 应用程序衍生产品)。微软的 WPF 和 Silverlight 架构师之一 John Gossman 于 2005 年在他的博客上宣布了 MVVM。

https://i.stack.imgur.com/guQtb.png


J
JosephDoggie

从实用的角度来看,MVC(Model-View-Controller)是一种模式。然而,当 MVC 用作 ASP.net MVC 时,当与实体框架 (EF) 和“动力工具”结合使用时,它是一种非常强大的、部分自动化的方法,用于将数据库、表和列引入网页,无论是完整的仅限 CRUD 操作或 R(检索或读取)操作。至少在我使用 MVVM 时,视图模型与依赖于业务对象的模型进行交互,而这些模型又是“手工制作”的,经过大量努力,幸运的是得到了与 EF 给出的一样好的模型开箱即用”。从实际编程的角度来看,MVC 似乎是一个不错的选择,因为它提供了许多开箱即用的实用程序,但仍有可能添加一些花里胡哨的东西。


A
Alon

我曾经认为MVC和MVVM是一样的。现在由于 Flux 的存在,我可以区分:

在 MVC 中,对于应用程序中的每个视图,您都有一个模型和一个控制器,所以我称之为视图、视图模型、视图控制器。该模式没有告诉您一个视图如何与另一个视图进行通信。因此,在不同的框架中,有不同的实现。例如,在某些实现中,控制器相互通信,而在其他实现中,有另一个组件在它们之间进行调解。甚至还有视图模型相互通信的实现,这是对 MVC 模式的突破,因为视图模型只能由视图控制器访问。

在 MVVM 中,每个组件都有一个视图模型。该模式没有指定视图应该如何影响视图模型,因此通常大多数框架只是在视图模型中包含控制器的功能。但是,MVVM 确实告诉您,您的视图模型的数据应该来自模型,这是整个模型不知道或自定义到特定视图。

为了演示差异,让我们以 Flux 模式为例。 Flux 模式告诉应用程序中的不同视图应该如何通信。每个视图都监听一个存储并使用调度程序触发操作。调度程序反过来告诉所有商店关于刚刚执行的操作,并且商店会自行更新。 Flux 中的存储对应于 MVVM 中的(通用)模型。它不是任何特定视图的习惯。所以通常人们在使用 React 和 Flux 时,每个 React 组件实际上都实现了 MVVM 模式。当一个动作发生时,视图模型调用调度器,最后它根据存储中的变化进行更新,也就是模型。你不能说每个组件都实现了 MVC,因为在 MVC 中只有控制器可以更新视图模型。所以 MVVM 可以和 Flux 一起工作(MVVM 处理视图和视图模型之间的通信,而 Flux 处理不同视图之间的通信),而 MVC 不能在不破坏关键原则的情况下与 Flux 一起工作。


M
Maulik

mvc 是服务器端,mvvm 是 Web 开发中的客户端(浏览器)。

大多数时候 javascript 用于浏览器中的 mvvm。 mvc 有很多服务器端技术。


C
Community

作为给出的许多回复的补充,我想从现代客户端 Web 或富 Web 应用程序的角度添加一些额外的视角。

事实上,如今简单的网站和大型 Web 应用程序通常使用许多流行的库(例如 Bootstrap)构建。 Knockout 由 Steve Sanderson 构建,提供对 MVVM 模式的支持,该模式模仿了该模式中最重要的行为之一:通过视图模型进行数据绑定。使用一点 JavaScript,可以实现数据和逻辑,然后可以使用简单的 data-bind HTML 属性将其添加到页面元素,类似于使用 Bootstrap 的许多功能。这两个库单独一起提供交互式内容。当与路由结合使用时,这种方法可以生成一种简单而强大的方法来构建单页应用程序

同样,现代客户端框架(例如 Angular)按照约定遵循 MVC 模式,但也添加了一个服务。有趣的是,它被吹捧为 Model-View-Whatever (MVW)。 (见this post on Stack Overflow。)

此外,随着 Angular 2 等渐进式 Web 框架的兴起,我们看到了术语的变化,也许还有一种新的架构模式,其中组件由视图或模板组成并与服务交互——所有这些都可以包含在一个模块;和一系列模块组成了应用程序。