标准的“模型视图控制器”模式和微软的模型/视图/视图模型模式之间有区别吗?
当前回答
据我所知,MVVM映射到MVC的MV——也就是说,在传统的MVC模式V不沟通直接与M .第二版本的MVC,之间有一个直接联系M和诉MVVM似乎把所有任务相关的M和V交流,和夫妻分离它的c .实际上,还有大范围应用程序工作流程(或实现的使用场景)中没有完全占MVVM。这就是控制器的作用。通过从控制器中删除这些较低级别的方面,它们更干净,更容易修改应用程序的使用场景和业务逻辑,也使控制器更具可重用性。
其他回答
使用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模式只是将该实践推广到所有UI元素。
而且这不是微软的模式,WPF / Silverlight数据绑定特别适合使用这种模式。但是没有什么能阻止您使用它与java服务器面,例如。
对于不太熟悉架构模式主题的人来说,其他答案可能不太容易理解。对应用程序架构不熟悉的人可能想知道它的选择在实践中如何影响她的应用程序,以及在社区中有什么大惊小怪的。
为了更好地解释上述问题,我编写了这个涉及MVVM、MVP和MVC的剧本。故事开始于一个用户点击电影搜索应用程序中的“FIND”按钮…
用户:单击…
观点:那是谁?[MVVM|MVP|MVC]
用户:我只是点击了搜索按钮……
视图:好的,稍等... .(MVVM MVP | | MVC)
(视图调用ViewModel|Presenter|Controller…)
视图:嘿,ViewModel|Presenter|Controller,一个用户刚刚点击了搜索按钮,我该怎么做?(MVVM MVP | | MVC)
ViewModel|Presenter|Controller:嘿View,这个页面上有搜索词吗?(MVVM MVP | | MVC)
查看:是的,…在这里…" piano " [MVVM|MVP|MVC]
这是MVVM和MVP|MVC之间最重要的区别
演示者|控制器:谢谢视图,…同时我正在模型上查找搜索词,请给他/她一个进度条[MVP|MVC]
(演示者|控制器正在调用模型…)
ViewModel:谢谢,我会在模型上查找搜索词,但不会直接更新你。相反,如果有任何结果,我将触发事件来searchResultsListObservable。所以你最好仔细观察一下。(MVVM)
(当在searchResultsListObservable中观察任何触发器时,视图认为它应该向用户显示一些进度条,因为ViewModel不会在那上面与它对话)
——————————————————————————————
ViewModel|演示者|控制器:嘿,模型,你有匹配这个搜索词吗?: " piano " [MVVM|MVP|MVC]
Model: Hey ViewModel|Presenter|Controller, let me check…[MVVM|MVP|MVC]
(模型正在向电影数据库查询…)[MVVM|MVP|MVC]
(过了一会儿……)
————这是MVVM, MVP和MVC————-之间的分歧点
模型:我为你找到了一个列表,ViewModel|Presenter,这里是JSON“[{" name ": "钢琴老师","年份":2001},{" name ": "钢琴","年份":1993}]" [MVVM|MVP]
模型:有一些结果可用,控制器。我已经在我的实例中创建了一个字段变量,并将其填充为结果。它的名字是searchResultsList [MVC]
(演示者|控制器感谢模型并返回视图)[MVP|MVC]
主持人:感谢您的等待,View,我为您找到了匹配结果的列表,并将它们以像样的格式排列:["钢琴老师2001″,"钢琴1993 "]。同时,现在请隐藏进度条[MVP]
控制器:感谢等待视图,我已经询问了模型关于你的搜索查询。它说它已经找到了一个匹配结果列表,并将它们存储在其实例内名为“searchResultsList”的变量中。你可以从那里得到它。同时,现在请隐藏进度条[MVC]
ViewModel: searchResultsListObservable上的任何观察者都将被通知有这样一个像样格式的新列表:[" Piano Teacher 2001″," Piano 1993 "]。
视图:非常感谢主讲人[MVP]
视图:谢谢你“控制器”[MVC](现在视图在问自己:我应该如何将我从模型得到的结果呈现给用户?电影的制作年份是先写还是后写?)
视图:哦,在searchResultsListObservable中有一个新的触发器…,很好,有一个像样的列表,现在我只需要在列表中显示它。有了结果之后,我还应该隐藏进度条。(MVVM)
如果你感兴趣,我在这里写了一系列文章,通过实现一个电影搜索android应用程序来比较MVVM、MVP和MVC。
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自由管理。
如果我还没有把你弄糊涂,试着联系我……我不介意用插图和例子详细讨论这个问题。
在一天结束的时候,我们都是程序员,当我们编码的时候,我们内心就会出现混乱……所以规则会被打破,理论会改变,所有这些最终都将成为垃圾……但在大型项目和大型团队中工作时,就设计模式达成一致并实施它确实很有帮助。总有一天,它会让你开始时多迈出的一小步,在以后变成一笔突飞猛进的积蓄。
一般来说,MVC用于Web开发,MVVM在WPF/Silverlight开发中最受欢迎。 然而,有时web架构可能混合使用MVC和MVVM。
例如:你可能会使用knockout.js,在这种情况下,你的客户端上会有MVVM。 你的MVC的服务器端也可以改变。在复杂的应用程序中,没有人使用纯模型。使用ViewModel作为MVC的“模型”可能有一定的意义,而你真正的模型基本上将是这个VM的一部分。这为您提供了一个额外的抽象层。