标准的“模型视图控制器”模式和微软的模型/视图/视图模型模式之间有区别吗?
当前回答
我认为要理解这些首字母缩略词的意思,最简单的方法就是暂时忘掉它们。相反,想想它们源自的软件,每一个软件。这实际上可以归结为早期网络和桌面之间的区别。
在2000年代中期,随着复杂性的增长,MVC软件设计模式(在20世纪70年代首次被描述)开始应用于web应用程序。想想数据库、HTML页面和中间的代码。让我们稍微改进一下以达到MVC:对于»database«,让我们假设数据库加接口代码。对于»HTML页面«,让我们假设HTML模板加上模板处理代码。对于»code inbetween«,让我们假设代码将用户单击映射到操作,可能会影响数据库,肯定会显示另一个视图。就是这样,至少为了比较的目的是这样的。
让我们保留这个网页的一个特性,不是像今天那样,而是像十年前那样,当时JavaScript还是一个低级的、卑鄙的烦恼,真正的程序员很好地避开了:HTML页面本质上是愚蠢和被动的。浏览器是一个瘦客户机,或者可以说是一个穷客户机。浏览器中没有智能。整页重载规则。每次都会重新生成»view«。
让我们记住,尽管这种网络方式风靡一时,但与桌面相比,它是非常落后的。桌面应用程序是胖客户端,也可以说是富客户端。(甚至像Microsoft Word这样的程序也可以被视为某种客户端,文档客户端。)他们是充满智慧的客户,对自己的数据了如指掌。他们是有状态的。它们在内存中缓存正在处理的数据。没有整页重载这种废话。
这种富桌面方式可能就是第二个首字母缩写MVVM的起源。不要被字母所迷惑,也不要被c的省略所迷惑。他们必须如此。没有东西被移除。我们只增加了一件事:状态性,缓存在客户端上的数据(以及处理这些数据的智能)。该数据(本质上是客户机上的缓存)现在被称为»ViewModel«。它允许丰富的交互性。就是这样。
MVC =模型、控制器、视图=本质上的单向通信=交互性差 MVVM =模型、控制器、缓存、视图=双向通信=丰富的交互性
我们可以看到,通过Flash、Silverlight,以及最重要的JavaScript, web已经拥抱了MVVM。浏览器不能再被合法地称为瘦客户机。看看它们的可编程性。看看他们的内存消耗。看看现代网页上所有的Javascript交互。
就我个人而言,我发现这个理论和缩略语业务更容易理解,看看它在具体现实中指的是什么。抽象的概念是有用的,特别是在具体的问题上,所以理解可能会有一个完整的循环。
其他回答
MVVM是表示模型模式的改进(有争议)。我说有争议,因为唯一的区别是WPF如何提供数据绑定和命令处理的能力。
MVVM将视图模型添加到混合中。这很重要,因为它允许您大量使用WPF的绑定方法,而无需将所有特定于UI的部分放在常规模型中。
我可能是错的,但是我不确定MVVM真的强迫控制器混合。我发现这个概念更符合:http://martinfowler.com/eaaDev/PresentationModel.html。我认为人们选择将其与MVC结合起来,而不是将其内置到模式中。
微软在这里提供了Windows环境中MVVM模式的解释。
这里有一个关键的部分:
在模型-视图-视图模型设计模式中,应用程序由以下部分组成 三个一般组成部分。 模型:这表示应用程序使用的数据模型。例如,在图片共享应用程序中,此层可能表示 设备上可用的图片集和用于读取和的API 写入图片库。 视图:应用通常由多个UI页面组成。显示给用户的每个页面都是MVVM术语中的一个视图。观点是 用于定义和设置用户所看到内容样式的XAML代码。的数据 从模型显示到用户,这是工作的 的当前状态为UI提供此数据 例如,在一个图片共享应用中,视图就是UI 向用户显示设备上的相册列表,其中的图片 一个相册,或者另一个向用户显示特定信息的相册 图片。 ViewModel: ViewModel将数据模型或简单的模型绑定到应用程序的UI或视图上 哪一个来管理模型中的数据并将数据作为一个集合公开 XAML UI或视图可以绑定到的属性。例如, 在图片共享应用中,ViewModel会显示一个相册列表, 并且为每个相册公开一个图片列表。UI是不可知论的 图片从何而来,如何获取。它只是 知道ViewModel所显示的一组图片,并显示它们 对用户。
MVC是受控环境,MVVM是响应式环境。
在受控的环境中,你应该有更少的代码和一个通用的逻辑源;它应该始终存在于控制器中。然而;在web世界中,MVC很容易被分为视图创建逻辑和视图动态逻辑。创建在服务器上,动态在客户端上。你在ASP中经常看到这种情况。与AngularJS结合在一起,而服务器将创建一个视图并传入一个模型并将其发送给客户端。然后客户端将与视图交互,在这种情况下,AngularJS将作为本地控制器介入。一旦提交模型或新模型,就会被传递回服务器控制器并进行处理。(因此循环继续,当使用套接字或AJAX等时,这种处理有很多其他的翻译,但总体上架构是相同的。)
MVVM是一个响应式环境,这意味着您通常编写的代码(例如触发器)将基于某些事件激活。在MVVM蓬勃发展的XAML中,使用内置的数据绑定框架可以轻松完成这一切,但如前所述,这将适用于任何视图、任何编程语言的任何系统。它不是多发性硬化症特有的。ViewModel会触发(通常是属性改变事件),View会根据你创建的触发器对它做出反应。这可能是技术性的,但底线是视图是无状态的,没有逻辑。它只是基于值更改状态。此外,viewmodel是无状态的,逻辑很少,而模型是逻辑本质为零的状态,因为它们应该只维护状态。我将其描述为应用程序状态(模型)、状态转换器(ViewModel),然后是可视状态/交互(视图)。
在MVC桌面或客户端应用程序中,你应该有一个模型,该模型应该由控制器使用。基于模型,控制器将修改视图。视图通常与带有接口的控制器绑定,以便控制器可以使用各种视图。在ASP。NET中的MVC逻辑在服务器上略微向后,因为控制器管理模型并将模型传递给选定的视图。然后,视图会根据模型填充数据,并拥有自己的逻辑(通常是另一个MVC集,例如用AngularJS完成的)。人们会争论并将其与应用程序MVC混淆,并试图同时做这两件事,而维护项目最终将成为一场灾难。使用MVC时,总是把逻辑和控件放在一个位置。不要在视图后面的代码中(或通过web的JS在视图中)写视图逻辑来容纳控制器或模型数据。让控制器改变视图。视图中应该存在的唯一逻辑是通过它所使用的接口创建和运行所需的任何逻辑。提交用户名和密码就是一个例子。无论是桌面还是网页(在客户端),只要视图触发提交动作,控制器就应该处理提交过程。如果做得正确,你总是可以很容易地找到MVC web或本地应用程序。
MVVM是我个人最喜欢的,因为它完全是反应性的。如果模型改变了状态,ViewModel会监听并转换状态,就这样!!然后,视图监听ViewModel的状态变化,并根据来自ViewModel的转换进行更新。有些人称之为纯粹的MVVM,但实际上只有一个,我不在乎你怎么争论,它总是纯粹的MVVM,其中视图完全不包含逻辑。
这里有一个小例子:假设你想要在按下按钮时滑动菜单。在MVC中,你的界面中会有一个MenuPressed动作。当你点击菜单按钮时,控制器会知道,然后告诉视图根据另一个接口方法(如SlideMenuIn)在菜单中滑动。为什么要往返?如果控制器决定你不能或想要做别的事情,这就是原因。控制器应该负责视图,视图什么都不做,除非控制器这么说。然而;在MVVM中,动画中的幻灯片菜单应该是内置的和通用的,而不是被告知滑动它将基于一些值这样做。它监听ViewModel当ViewModel说IsMenuActive = true时动画就会发生。现在,说到这里,我想非常清楚地说明另一点,请注意。IsMenuActive可能是糟糕的MVVM或ViewModel设计。在设计ViewModel时,你永远不应该假设视图会有任何特性,而只是传递转换后的模型状态。这样,如果你决定更改视图以删除菜单,只是以另一种方式显示数据/选项,ViewModel不会关心。那么您将如何管理菜单呢?当数据有意义时,就是这样。因此,一种方法是给菜单一个选项列表(可能是内部ViewModels的数组)。如果该列表有数据,菜单就知道通过触发器打开,如果没有,它就知道通过触发器隐藏。你只是在ViewModel中有菜单的数据。不要决定在ViewModel中显示/隐藏数据。简单地转换模型的状态。通过这种方式,视图是完全响应式和通用的,可以在许多不同的情况下使用。
如果你还不熟悉它们的架构,那么这一切可能完全没有意义,因为你会在网上发现很多不好的信息,学习起来可能会非常混乱。
所以…要做到这一点,需要记住以下几点。预先决定如何设计应用程序,并坚持下去。
如果你使用MVC,这很好,那么确保你的控制器是可管理的,并完全控制你的视图。如果你有一个大的视图,可以考虑在视图中添加具有不同控制器的控件。只是不要将这些控制器级联到不同的控制器上。维护起来非常令人沮丧。花点时间把东西分开设计,让它们作为独立的组件工作……并且总是让控制器告诉模型提交或持久化存储。MVC的理想依赖设置是视图←控制器→模型或ASP。模型←视图↔控制器→模型(从控制器到视图,模型可以相同,也可以完全不同)…当然,此时唯一需要知道的是视图中的控制器,主要是为了端点参考,以知道在哪里返回传递模型。
如果你做MVVM,我祝福你善良的灵魂,但要花时间做对!不要使用接口。让视图根据值来决定它的外观。使用模拟数据处理视图。如果你最终有一个视图显示你的菜单(如例),即使你不想要它的时候,那么好。你的视图按照它应该的方式工作,并根据它应该的值做出反应。只需向触发器添加一些需求,以确保ViewModel处于特定的转换状态时不会发生这种情况,或者命令ViewModel清空该状态。在你的ViewModel中,不要用内部逻辑删除它,就好像你在决定视图是否应该看到它一样。记住,你不能假设ViewModel中有或没有菜单。最后,模型应该允许您更改和存储状态。这是验证和所有事情发生的地方;例如,如果模型不能修改状态,那么它将简单地将自己标记为脏或其他东西。当ViewModel意识到这一点时,它会转换脏的东西,然后视图会意识到这一点,并通过另一个触发器显示一些信息。视图中的所有数据都可以绑定到ViewModel,因此一切都可以是动态的,只有模型和ViewModel完全不知道视图将如何对绑定做出反应。事实上,模型也没有ViewModel的概念。当设置依赖项时,它们应该这样指向,而且只这样指向View→ViewModel→Model(这里还有一个边注…这可能也会引起争论,但我不在乎……不要将模型传递给视图,除非该模型是不可变的;否则用适当的ViewModel包装它。视图不应该看到模型周期。我说你看过什么演示或者你是怎么做的,这是错误的。)
这是我的最后一个建议……看看一个设计良好但非常简单的MVC应用程序,并对MVVM应用程序进行同样的操作。一个将有更多的控制,限制到零灵活性,而另一个将没有控制和无限的灵活性。
受控环境非常适合从一组控制器或(单个源)管理整个应用程序,而响应式环境可以被分解为单独的存储库,完全不知道应用程序的其余部分在做什么。微观管理vs自由管理。
如果我还没有把你弄糊涂,试着联系我……我不介意用插图和例子详细讨论这个问题。
在一天结束的时候,我们都是程序员,当我们编码的时候,我们内心就会出现混乱……所以规则会被打破,理论会改变,所有这些最终都将成为垃圾……但在大型项目和大型团队中工作时,就设计模式达成一致并实施它确实很有帮助。总有一天,它会让你开始时多迈出的一小步,在以后变成一笔突飞猛进的积蓄。
除了给出的许多回答之外,我还想从现代客户端web或富web应用程序的角度添加一些额外的观点。
事实上,现在简单的网站和较大的网络应用程序通常是用许多流行的库(如Bootstrap)构建的。Knockout由Steve Sanderson构建,提供了对MVVM模式的支持,该模式模仿了模式中最重要的行为之一:通过视图模型进行数据绑定。只需一点点JavaScript,就可以实现数据和逻辑,然后使用简单的数据绑定HTML属性将其添加到页面元素中,类似于使用Bootstrap的许多特性。这两个库单独提供互动内容;当与路由结合使用时,这种方法可以产生一种简单而强大的方法来构建单页应用程序。
类似地,现代客户端框架(如Angular)遵循MVC模式,但也添加了一个服务。有趣的是,它被吹捧为模型-视图- whatever (MVW)。(参见Stack Overflow上的这篇文章。)
此外,随着渐进式web框架(如Angular 2)的兴起,我们看到了术语的变化,也许还有一种新的架构模式,组件由视图或模板组成,并与服务交互——所有这些都可以包含在模块中;和一系列模块组成的应用程序。