题 什么是MVP和MVC,有什么区别?


当超越时 RAD (拖放和配置)构建用户界面的方式,许多工具鼓励你可能会遇到三种设计模式 模型 - 视图 - 控制器模型 - 视图 - 演示 和 模型 - 视图 - 视图模型。我的问题有三个部分:

  1. 这些模式解决了哪些问题?
  2. 它们有什么相似之处?
  3. 他们有什么不同?

1839
2017-08-05 10:06


起源


mvc.givan.se/#mvp - givanse
IDK,但据说是原始的MVC,它意味着在小型中使用。每个按钮,标签等都有自己的视图和控制器对象,或者至少是Uncle Bob所声称的。我认为他在谈论Smalltalk。在YouTube上查看他的演讲,他们很有吸引力。 - still_dreaming_1
MVP通过将View-Controller拆分为View和Presenter来添加额外的间接层... - the_prole
主要区别在于,在MVC中,Controller不会将任何数据从Model传递给View。它只是通知View从模型本身获取数据。但是,在MVP中,View和Model之间没有任何关联。 Presenter本身从模型中获取所需的任何数据,并将其传递给View以显示。更多内容与所有架构模式中的android示例一起在这里: digigene.com/category/android/android-architecture - Ali Nem


答案:


模型 - 视图 - 演示

MVP,Presenter包含View的UI业务逻辑。 View中的所有调用都直接委托给Presenter。 Presenter也直接与View分离,并通过界面与之对话。这是为了允许在单元测试中模拟View。 MVP的一个常见属性是必须进行大量的双向调度。例如,当有人单击“保存”按钮时,事件处理程序将委托给Presenter的“OnSave”方法。保存完成后,Presenter将通过其界面回调View,以便View可以显示保存已完成。

MVP往往是在Web窗体中实现单独呈现的非常自然的模式。原因是View总是首先由ASP.NET运行时创建。您可以 了解有关两种变体的更多信息

两个主要变化

被动观点: 视图尽可能愚蠢,几乎没有逻辑。演示者是一个与视图和模型对话的中间人。视图和模型完全相互屏蔽。模型可能会引发事件,但Presenter会订阅它们以更新视图。在Passive View中没有直接数据绑定,而View公开了Presenter用于设置数据的setter属性。所有状态都在Presenter中管理,而不是View。

  • Pro:最大可测性表面;清晰分离视图和模型
  • Con:更多工作(例如所有setter属性),因为您自己正在进行所有数据绑定。

监督控制员: Presenter处理用户手势。 View直接通过数据绑定绑定到Model。在这种情况下,Presenter的工作是将Model传递给View,以便它可以绑定到它。 Presenter还将包含手势逻辑,如按下按钮,导航等。

  • Pro:通过利用数据绑定,减少了代码量。
  • Con:表面上可测试的表面较少(因为数据绑定),并且View中的封装较少,因为它直接与Model进行对话。

模型 - 视图 - 控制器

在里面 MVC,Controller负责确定响应任何操作(包括应用程序加载时)显示的视图。这与MVP不同,其中操作通过View路由到Presenter。在MVC中,View中的每个操作都与对Controller的调用以及操作相关联。在网络中,每个动作都涉及对URL的调用,在URL的另一侧有一个Controller响应。控制器完成处理后,将返回正确的视图。在整个应用程序的生命周期中,序列以这种方式继续:

视图中的操作
         - >致电控制器
         - >控制器逻辑
         - > Controller返回View。

MVC的另一个重要区别是View不直接绑定到Model。视图简单地呈现,并且完全是无状态的。在MVC的实现中,View通常在后面的代码中没有任何逻辑。这与MVP完全相反,因为如果View没有委托给Presenter,它将永远不会被调用。

演示模型

另一种要看的模式是 演示模型 模式。在这种模式中没有Presenter。相反,View直接绑定到Presentation Model。 Presentation Model是专为View设计的模型。这意味着该模型可以公开一个永远不会放在域模型上的属性,因为它会违反关注点分离。在这种情况下,表示模型绑定到域模型,并可以订阅来自该模型的事件。 View然后订阅来自Presentation Model的事件并相应地更新自身。 Presentation Model可以公开视图用于调用操作的命令。这种方法的优点在于,您可以完全删除代码隐藏,因为PM完全封装了视图的所有行为。这种模式非常适合在WPF应用程序中使用,也称为 模型 - 视图 - 视图模型

有一个 关于Presentation Model的MSDN文章 和一节 WPF复合应用指南 (前棱镜)讲述 分离的演示模式


1803
2017-08-05 10:21



你能澄清这句话吗? 这与MVP不同,其中操作通过View路由到Presenter。在MVC中,View中的每个操作都与对Controller的调用以及操作相关联。 对我来说,这听起来像是一回事,但我相信你会描述一些与众不同的东西。 - Panzercrisis
@Panzercrisis我不确定这是否是作者的意思,但这是我认为他们试图说的。喜欢这个答案 - stackoverflow.com/a/2068/74556 提到,在MVC中,控制器方法基于行为 - 换句话说,您可以将多个视图(但相同的行为)映射到单个控制器。在MVP中,演示者更靠近视图耦合,并且通常导致更接近一对一的映射,即视图动作映射到其对应的演示者的方法。您通常不会将另一个视图的操作映射到另一个演示者(来自另一个视图)方法。 - Dustin Kendall


我曾经在博客上写过这篇文章 Todd Snyder关于两者之间差异的优秀帖子

以下是两者之间的主要区别   模式:

MVP模式

  • 视图与模型更加松散耦合。主持人是   负责将模型绑定到   风景。
  • 更容易进行单元测试,因为与视图的交互是通过   一个界面
  • 通常一对一地查看演示者地图。复杂的观点可能有   多位主持人。

MVC模式

  • 控制器基于行为,可以跨越共享   意见
  • 可以负责确定要显示的视图

这是我能找到的网上最好的解释。


385
2017-07-06 22:18



我不明白在两种情况下,视图中是如何或多或少地与模型耦合的,因为整个点都要完全解耦它们。我并不是说你说错了什么 - 只是对你的意思感到困惑。 - Bill K
@pst:MVP真的是1 View = 1 Presenter。使用MVC,Controller可以管理多个视图。就是这样,真的。使用“tabs”模型可以想象每个选项卡都有自己的Presenter,而不是所有选项卡都有一个Controller。 - Jon Limjap
最初有两种类型的控制器:您说过在多个视图中共享的控制器,以及特定于视图的控制器,主要用于调整共享控制器的接口。 - Acsor
@JonLimjap无论如何,一个视图意味着什么?在iOS编程的背景下,它是一个屏幕吗?这是否使iOS的控制器更像MVP而不是MVC? (另一方面,每个屏幕也可以有多个iOS控制器) - huggie
托德对MVC的图解说明完全与将视图和模型分离的想法相矛盾。如果您查看图表,它会显示模型更新视图(从模型到视图的箭头)。在哪个宇宙是一个系统,模型直接与视图交互,一个解耦的? - Ash


这是对这些设计模式的许多变体的过度简化,但这就是我喜欢考虑两者之间差异的方式。

MVC

MVC

MVP

enter image description here


367
2017-09-12 20:47



这是对原理图的一个很好的描述,显示了从演示者的API中任何GUI相关(查看内容)的抽象和完全隔离。一个小问题:可以在只有一个演示者的情况下使用主演示者,而不是每个视图一个,但您的图表是最干净的。 IMO,MVC / MVP之间最大的区别在于MVP试图使视图完全没有显示当前“视图状态”(视图数据)以外的任何内容,同时也禁止视图任何Model对象的知识。因此需要在那里的接口注入该状态。
好图片。我使用MVP非常多,所以我想提出一点。根据我的经验,演示者需要经常互相交谈。模型(或业务对象)也是如此。由于这些额外的“蓝线”通信将出现在您的MVP图片中,因此Presenter-Model关系可能变得非常纠结。因此,我倾向于保持一对一的Presenter-Model关系与一对多关系。是的,它需要在模型上使用一些额外的委托方法,但如果模型的API发生变化或需要重构,它会减少许多令人头疼的问题。 - splungebob
MVC的例子是错的;视图和控制器之间存在严格的1:1关系。根据定义,控制器解释人类手势输入以为单个控件生成模型和视图的事件。更简单地说,MVC仅用于单独的小部件。一个小部件,一个视图,一个控件。 - Samuel A. Falvo II
@ SamuelA.FalvoII并非总是如此,ASP.NET MVC中的控制器和视图之间存在1:很多: stackoverflow.com/questions/1673301/... - StuperUser
@StuperUser - 当我写这篇文章时,不确定我在想什么。当然,你是对的,回头看我写的东西,我不得不怀疑自己是否有其他的背景,我没有说清楚。谢谢你的纠正。 - Samuel A. Falvo II


以下是代表通信流程的插图

enter image description here 

enter image description here


210
2017-08-25 21:22



我对MVC图有疑问。我没有得到视图出来的部分来获取数据。我认为控制器将转发到具有所需数据的视图。 - Brian Rizo
如果用户单击按钮,那么该怎么不与视图交互?我觉得在MVC中,用户与视图的交互比控制器更多 - Jonathan
我知道这是一个陈旧的答案 - 但任何人都可以回复@JonathanLeaders点吗?我来自winforms背景,除非你做了一些非常独特的编码,当你点击UI / View之前获得该点击的知识之前。至少,据我所知? - Rob P.
@RobP。我认为这些类型的图表往往过于复杂或过于简单。 Imo MVP图表的流程也适用于MVC应用程序。根据语言特性(数据绑定/观察者),可能存在变化,但最终的想法是将视图与应用程序的数据/逻辑分离。 - Luca Fülbier
@JonathanLeaders人们有 真 当他们说“MVC”时,他们会想到不同的东西。创建此图表的人可能考虑了经典的Web MVC,其中“用户输入”是HTTP请求,“返回给用户的视图”是呈现的HTML页面。因此,从经典Web MVC应用程序的作者的角度来看,用户和视图之间的任何交互都“不存在”。 - cubuspl42


MVP是  必然是View负责的场景(例如,参见Taligent的MVP)。
我发现不幸的是,人们仍在宣传这种模式(负责观点),而不是反模式,因为它与“它只是一种观点”(实用程序员)相矛盾。 “这只是一种观点”指出向用户显示的最终视图是应用程序的次要问题。微软的MVP模式使得重复使用Views变得更加困难 便利地 借助微软的设计师鼓励不良做法。

坦率地说,我认为MVC的基本关注对任何MVP实现都适用,差异几乎完全是语义的。只要您关注视图(显示数据),控制器(初始化和控制用户交互)和模型(基础数据和/或服务)之间的关注点分离,那么您就可以实现MVC的优势。如果您正在获得好处,那么谁真正关心您的模式是MVC,MVP还是监督控制器?唯一的 真实 模式仍然是MVC,其余的只是不同的风格。

考虑 这个 非常令人兴奋的文章,全面列出了许多这些不同的实现。 您可能会注意到,他们基本上都在做同样的事情,但略有不同。

我个人认为MVP最近才被重新引入作为一个吸引人的术语,要么减少语义偏执者之间的争论,他们争论某些东西是否真的是MVC,或者证明微软快速应用程序开发工具的合理性。在我的书中,这些原因都不能证明它作为一种单独的设计模式存在。


149
2017-08-06 22:51



我已经阅读了几个关于MVC / MVP / MVVM / etc之间差异的答案和博客。实际上,当你开始做生意时,它们都是一样的。无论您是否有接口,以及您是否使用了setter(或任何其他语言功能),这并不重要。似乎这些模式之间的差异源于各种框架实现的差异,而不是概念问题。 - Michael
我不打电话给MVP 反模式,后面的帖子“......其余的[包括MVP]只是[MVC]的不同风格......”,这意味着如果MVP是一个反模式,那么MVC ......它只是一种风味一种不同的框架方法。 (现在,有些人 具体 MVP实现可能比某些实现或多或少 具体 针对不同任务的MVC实现......)
@Quibblsome:“我个人认为MVP最近才被重新引入作为一个吸引人的术语,要么减少语义偏执者之间的争论,他们争论某些东西是否真的是MVC [...]我的书中的这两个理由都没有证明它的存在是正确的单独的设计模式。“它的不同之处在于它与众不同。在MVP中,视图可以是满足预定义接口的任何内容(MVP中的视图是独立组件)。在MVC中,Controller是针对特定视图而制作的(如果关系的优点可能会让某人认为值得另一个术语)。 - Hibou57
@ Hibou57,没有什么可以阻止MVC将视图作为接口引用或为几个不同的视图创建通用控制器。 - Quibblesome
@quibblesome其实,有。根据定义,控制器与其相应的视图紧密绑定,因为他们的工作是将人类手势(按键,鼠标更新等)解释为事件 个人控制 在窗户上。这就是为什么你有一个严格的控制器,一个视图关系。控制器是 决不 旨在用于整个表格。对于表单范围的使用,应用程序模型(又名表示模型)应运而生,它更适合该目的。由于非Smalltalk GUI不依赖于MVC来实现控件,因此MVC在实践中的意义相对较小。 - Samuel A. Falvo II


MVP:视图负责。

在大多数情况下,视图会创建其演示者。演示者将与模型交互并通过界面操纵视图。视图有时会与演示者交互,通常通过某种界面进行交互。这归结为实施;您希望视图在演示者上调用方法还是希望视图具有演示者侦听的事件?它归结为:视图了解演示者。视图委托给演示者。

MVC:控制器负责。

根据某些事件/请求创建或访问控制器。然后,控制器创建适当的视图并与模型交互以进一步配置视图。它归结为:控制器创建和管理视图;视图是控制器的从属。视图不知道控制器。


90
2017-12-20 02:10



“View不了解Controller。”我认为您的意思是该视图与模型没有直接联系? - Lotus Notes
视图永远不应该知道模型中的模型。 - Brian Leahy
@Brian:“大多数情况下,View会创建它的Presenter。”我主要看到相反的情况,Presenter启动了模型和视图。好吧,View也可以推出Presenter,但这一点并不是最有特色的。最重要的是在一生中后期发生的事情。 - Hibou57
您可能希望编辑您的答案以进一步解释:由于View不了解Controller,因此用户操作如何在用户在屏幕上看到的“可视”元素(即视图)上执行,并传达给Controller ... - Ash


enter image description here

MVC(模型视图控制器)

输入首先指向Controller,而不是视图。该输入可能来自与页面交互的用户,但也可能只是将特定URL输入到浏览器中。在任何一种情况下,它都是一个与之连接的控制器,以启动一些功能。 Controller和View之间存在多对一关系。这是因为单个控制器可以基于正在执行的操作选择要呈现的不同视图。 请注意从Controller到View的单向箭头。这是因为View对控制器没有任何了解或参考。 Controller确实传回了Model,因此View和传递给它的预期模型之间存在知识,但是不是Controller提供它。

MVP(模型视图演示者)

输入以View开头,而不是Presenter。 View和关联的Presenter之间存在一对一映射。 View包含对Presenter的引用。 Presenter也对从View触发的事件做出反应,因此它知道与之关联的View。 Presenter根据它在Model上执行的请求操作更新View,但View不支持Model。

更多 参考


62
2017-08-05 10:22



但在 MVP 模式,当应用程序第一次加载时,是不是演示者负责加载第一个视图?例如,当我们加载facebook应用程序时,主持人是否负责加载登录页面? - viper
MVC中从Model到View的链接?在给定此链接的情况下,您可能希望编辑您的答案以解释如何使其成为“解耦”系统。提示:你可能会觉得很难。此外,除非您认为读者会愉快地接受他们一生都在计算错误,否则您可能想要详细阐述为什么操作首先在MVC中通过Controller,尽管用户与屏幕上的“视觉”元素进行交互(即查看),而不是处理后面的一些抽象层。 - Ash
这应该是公认的答案。简洁明了 - Nelson Ramirez


  • MVP =模型 - 视图 - 演示者
  • MVC =模型 - 视图 - 控制器

    1. 两种表现形式。它们分隔了模型(思考域对象),屏幕/网页(视图)以及UI应该如何表现之间的依赖关系(演示者/控制器)
    2. 它们在概念上非常相似,人们根据品味不同地初始化Presenter / Controller。
    3. 一篇关于差异的伟大文章是 这里。最值得注意的是MVC模式具有模型更新视图。

31
2017-08-08 05:55



模型更新VIew。这仍然是一个解耦系统? - Ash


另外值得记住的是,MVP也有不同类型。福勒已经将模式分解为两个 - 被动视图和监督控制器。

使用被动视图时,View通常会实现细粒度的界面,其属性或多或少地直接映射到底层UI小部件。例如,您可能拥有一个ICustomerView,其中包含Name和Address等属性。

您的实现可能如下所示:

public class CustomerView : ICustomerView
{
    public string Name
    { 
        get { return txtName.Text; }
        set { txtName.Text = value; }
    }
}

您的Presenter类将与模型对话并将其“映射”到视图中。这种方法称为“被动视图”。好处是视图易于测试,并且在UI平台(Web,Windows / XAML等)之间移动更容易。缺点是你不能利用像数据绑定这样的东西  像框架一样强大 WPF 和 Silverlight的)。

MVP的第二种风格是监督控制器。在这种情况下,您的View可能有一个名为Customer的属性,然后再将其数据绑定到UI小部件。您不必考虑同步和微观管理视图,监督控制器可以在需要时介入并提供帮助,例如使用编译的交互逻辑。

MVP的第三个“风味”(或者有人可能称之为单独的模式)是Presentation Model(或者有时称为Model-View-ViewModel)。与MVP相比,您将M和P“合并”为一个类。您拥有UI小部件所绑定的客户对象,但您还有其他UI特定字段,如“IsButtonEnabled”或“IsReadOnly”等。

我认为我在UI架构中找到的最好的资源是Jeremy Miller所做的一系列博客文章 构建自己的CAB系列目录。他涵盖了MVP的所有风格,并展示了C#代码来实现它们。

我还在Silverlight over的上下文中写了关于Model-View-ViewModel模式的博客 YouCard重新访问:实现ViewModel模式


31
2018-04-06 13:51





问题有很多答案,但我觉得需要一些非常简单的答案,清楚地比较两者。以下是用户在MVP和MVC应用中搜索电影名称时所做的讨论:

用户:点击点击...

视图: 那是谁? [MVP|MVC]

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

视图:好的,等一下...... [MVP|MVC]

视图 打电话给 主持人|调节器 ......)[MVP|MVC]

视图:嘿 主持人|调节器,用户刚刚点击了搜索按钮,我该怎么办? [MVP|MVC]

主持人|调节器:嘿 视图,该页面上是否有搜索字词? [MVP|MVC]

视图:是的,......这里是......“钢琴”[MVP|MVC]

主持人: 谢谢 视图,...同时我正在查找搜索词 模型,请告诉他/她一个进度条[MVP|MVC]

主持人|调节器 正在呼唤 模型 ......)[MVP|MVC]

主持人|调节器:嘿 模型,你对这个搜索词有什么匹配吗?:“piano”[MVP|MVC]

模型:嘿 主持人|调节器,让我查一下...... [MVP|MVC]

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

( 过了一会儿 ... )

--------------这是MVP和MVC开始分歧的地方---------------

模型:我找到了一份清单, 主持人,这里是JSON“[{”name“:”Piano Teacher“,”year“:2001},{”name“:”Piano“,”year“:1993}]”[MVP]

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

主持人|调节器 谢谢 模型 然后回到 视图)[MVP|MVC]

主持人:谢谢你的等待 视图,我找到了一份匹配结果列表,并以一种可呈现的格式排列:[“钢琴老师2001”,“钢琴1993”]。请在垂直列表中向用户显示。也请现在隐藏进度条[MVP]

调节器:谢谢你的等待 视图, 我问过了 模型 关于您的搜索查询。它说它找到了一个匹配结果列表,并将它们存储在其实例中名为“searchResultsList”的变量中。你可以从那里得到它。也请现在隐藏进度条[MVC]

视图: 非常感谢你 主持人 [MVP]

视图:谢谢你“控制器”[MVC] (现在 视图 质疑自己:我应该如何呈现我从中得到的结果 模型 对用户?电影的制作年份应该是第一个还是最后一个......?它应该是垂直还是水平列表? ...)

如果您有兴趣,我一直在撰写一系列文章,涉及应用程序架构模式(MVC,MVP,MVVP,清洁架构......)以及Github回购 这里。即使样本是为Android编写的,基本原则也可以应用于任何媒介。


18
2017-08-05 10:20