标准的“模型视图控制器”模式和微软的模型/视图/视图模型模式之间有区别吗?
当前回答
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代码生成框架实现了MVVM和类似于Prism的模式,它还大量使用控制器来分离所有用例逻辑。
不要认为控制器已经被视图模型淘汰了。
我已经开始了一个关于这个主题的博客,当我可以的时候,我会添加进去(只有当主机丢失时存档)。将MVCVM与通用导航系统相结合存在一些问题,因为大多数导航系统只使用视图和vm,但我将在后面的文章中讨论这个问题。
使用MVCVM模型的另一个好处是,在应用程序的生命周期中,只有控制器对象需要存在于内存中,并且控制器主要包含代码和少量的状态数据(即很小的内存开销)。与需要保留视图模型的解决方案相比,这大大减少了应用程序的内存密集型,并且非常适合某些类型的移动开发(例如使用Silverlight/Prism/MEF的Windows mobile)。这当然取决于应用程序的类型,因为您可能仍然需要保留偶尔缓存的虚拟机来响应。
注意:这篇文章已经编辑了很多次,并没有特别针对所提出的狭窄问题,所以我更新了第一部分,现在也包括了这个问题。在下面的评论中,大部分讨论只与ASP有关。而不是更广阔的图景。本文旨在介绍MVVM在Silverlight、WPF和ASP中的广泛使用。Net,并试图阻止人们用ViewModels替换控制器。
其他回答
使用MVC将强类型视图模型注入到视图中
控制器负责更新ViewModel并将其注入View中。(用于get请求) ViewModel是DataContext和视图状态(如最后选中的项目等)的容器。 模型包含数据库实体,非常接近数据库模式,它进行查询和过滤。(我喜欢EF和LINQ) 模型还应该考虑存储库和或将结果投影到强类型(EF有一个很好的方法……EF.Database。选择(querystring, parms)直接ADO访问注入查询和返回强类型。这解决了EF是缓慢的参数。EF并不慢! ViewModel获取数据并执行业务规则和验证 post后面的控制器将调用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);
}
注意,为了让上面的actionmethod像你想要的那样工作,你必须定义一个空CTOR来初始化post中没有返回的东西。回发也必须回发那些发生变化的名称/值对。如果缺少名称/值对,MVC绑定引擎就会做正确的事情,而这根本不是什么!如果发生这种情况,你可能会发现自己说“我正在丢失回post的数据”…
这种模式的优点是ViewModel做了所有“杂乱”的工作,接口到模型/业务逻辑,控制器只是一个路由器。这是SOC在起作用。
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代码生成框架实现了MVVM和类似于Prism的模式,它还大量使用控制器来分离所有用例逻辑。
不要认为控制器已经被视图模型淘汰了。
我已经开始了一个关于这个主题的博客,当我可以的时候,我会添加进去(只有当主机丢失时存档)。将MVCVM与通用导航系统相结合存在一些问题,因为大多数导航系统只使用视图和vm,但我将在后面的文章中讨论这个问题。
使用MVCVM模型的另一个好处是,在应用程序的生命周期中,只有控制器对象需要存在于内存中,并且控制器主要包含代码和少量的状态数据(即很小的内存开销)。与需要保留视图模型的解决方案相比,这大大减少了应用程序的内存密集型,并且非常适合某些类型的移动开发(例如使用Silverlight/Prism/MEF的Windows mobile)。这当然取决于应用程序的类型,因为您可能仍然需要保留偶尔缓存的虚拟机来响应。
注意:这篇文章已经编辑了很多次,并没有特别针对所提出的狭窄问题,所以我更新了第一部分,现在也包括了这个问题。在下面的评论中,大部分讨论只与ASP有关。而不是更广阔的图景。本文旨在介绍MVVM在Silverlight、WPF和ASP中的广泛使用。Net,并试图阻止人们用ViewModels替换控制器。
除了给出的许多回答之外,我还想从现代客户端web或富web应用程序的角度添加一些额外的观点。
事实上,现在简单的网站和较大的网络应用程序通常是用许多流行的库(如Bootstrap)构建的。Knockout由Steve Sanderson构建,提供了对MVVM模式的支持,该模式模仿了模式中最重要的行为之一:通过视图模型进行数据绑定。只需一点点JavaScript,就可以实现数据和逻辑,然后使用简单的数据绑定HTML属性将其添加到页面元素中,类似于使用Bootstrap的许多特性。这两个库单独提供互动内容;当与路由结合使用时,这种方法可以产生一种简单而强大的方法来构建单页应用程序。
类似地,现代客户端框架(如Angular)遵循MVC模式,但也添加了一个服务。有趣的是,它被吹捧为模型-视图- whatever (MVW)。(参见Stack Overflow上的这篇文章。)
此外,随着渐进式web框架(如Angular 2)的兴起,我们看到了术语的变化,也许还有一种新的架构模式,组件由视图或模板组成,并与服务交互——所有这些都可以包含在模块中;和一系列模块组成的应用程序。
在MVVM中,控制器不会被ViewModel取代,因为ViewModel的功能与控制器完全不同。你仍然需要一个控制器,因为如果没有控制器,你的模型、视图模型和视图就做不了什么…在MVVM中你也有一个控制器,MVVM这个名字是错误的。
在我看来,MVVMC是正确的名字。
正如你所看到的,ViewModel只是MVC模式的一个附加。它将转换逻辑(例如将对象转换为字符串)从控制器移动到ViewModel。
我曾经认为MVC和MVVM是一样的。现在,由于Flux的存在,我可以分辨出其中的区别:
在MVC中,对于你应用中的每个视图,你都有一个模型和一个控制器,我称之为视图,视图模型,视图控制器。该模式并没有告诉您一个视图如何与另一个视图通信。因此,在不同的框架中有不同的实现。例如,在某些实现中,控制器之间相互通信,而在其他实现中,有另一个组件在它们之间进行中介。甚至还有视图模型相互通信的实现,这打破了MVC模式,因为视图模型应该只由视图控制器访问。
在MVVM中,每个组件都有一个视图模型。该模式没有指定视图应该如何影响视图模型,所以通常大多数框架只在视图模型中包含控制器的功能。但是,MVVM确实告诉您,视图模型的数据应该来自模型,这是整个模型,它不知道或自定义特定的视图。
为了说明差异,让我们以Flux模式为例。Flux模式告诉我们应用中的不同视图应该如何通信。每个视图侦听一个存储,并使用分派器触发操作。分派程序依次将刚刚执行的操作告知所有存储,然后存储更新自己。Flux中的存储对应于MVVM中的(通用)模型。它不是针对任何特定视图定制的。所以通常当人们使用React和Flux时,每个React组件实际上都实现了MVVM模式。当一个动作发生时,视图模型调用分派器,最后它根据存储(即模型)中的变化得到更新。你不能说每个组件都实现了MVC,因为在MVC中只有控制器才能更新视图模型。因此MVVM可以和Flux一起工作(MVVM处理视图和视图模型之间的通信,Flux处理不同视图之间的通信),而MVC不能在不破坏关键原则的情况下与Flux一起工作。