当超越RAD(拖放和配置)构建用户界面的方式时,许多工具鼓励您使用三种设计模式,分别称为Model-View-Controller,Model-View-Presenter和Model-View-ViewModel。我的问题包括三个部分:
- 这些模式解决了哪些问题?
- 它们有何相似之处?
- 它们有何不同?
当超越RAD(拖放和配置)构建用户界面的方式时,许多工具鼓励您使用三种设计模式,分别称为Model-View-Controller,Model-View-Presenter和Model-View-ViewModel。我的问题包括三个部分:
Answers:
在MVP中,Presenter包含视图的UI业务逻辑。View委托的所有调用均直接传递给Presenter。演示者也直接从视图中分离出来,并通过界面与之对话。这是为了在单元测试中模拟View。MVP的一个共同属性是必须有很多双向分配。例如,当某人单击“保存”按钮时,事件处理程序将委托给演示者的“ OnSave”方法。保存完成后,演示者将通过其界面回调视图,以便视图可以显示保存已完成。
MVP往往是在Web窗体中实现独立表示的非常自然的模式。原因是View总是首先由ASP.NET运行时创建。您可以找到有关这两种变体的更多信息。
被动视图:视图尽可能愚蠢,并且包含几乎为零的逻辑。演示者是与视图和模型对话的中间人。视图和模型完全相互屏蔽。模型可以引发事件,但是演示者订阅了这些事件以更新视图。在Passive View中,没有直接的数据绑定,而是View公开了Presenter用于设置数据的setter属性。所有状态都在Presenter中管理,而不是在View中管理。
监督控制器:演示者处理用户手势。视图通过数据绑定直接绑定到模型。在这种情况下,演示者的工作是将模型传递给视图,以便可以绑定到视图。演示者还将包含手势的逻辑,例如按下按钮,导航等。
在MVC中,控制器负责确定响应于任何操作(包括应用程序何时加载)显示哪个视图。这与MVP不同,在MVP中,操作通过视图路由到演示者。在MVC中,视图中的每个动作都与对控制器的调用以及一个动作相关联。在网络中,每个动作都涉及对URL的调用,在该URL的另一侧有一个Controller响应。该控制器完成处理后,将返回正确的视图。该序列在应用程序的整个生命周期中都以这种方式继续:
视图中的操作 ->呼叫控制器 ->控制器逻辑 ->控制器返回视图。
关于MVC的另一大区别是,视图不直接绑定到模型。该视图只是呈现,并且是完全无状态的。在MVC的实现中,视图中的代码通常不会包含任何逻辑。这与绝对必要的MVP相反,因为如果View不委托给Presenter,它将永远不会被调用。
另一个要看的模式是演示模型图案。在这种模式下,没有演示者。相反,视图直接绑定到演示模型。Presentation Model是专门为View设计的模型。这意味着该模型可以公开一个永远不会放在域模型上的属性,因为这将违反关注点分离。在这种情况下,表示模型绑定到域模型,并且可以订阅来自该模型的事件。然后,View订阅来自Presentation Model的事件并相应地更新自身。Presentation Model可以公开视图用于调用动作的命令。这种方法的优点是,由于PM完全封装了视图的所有行为,因此您基本上可以完全删除后面的代码。模型-视图-视图模型。
在MSDN上有关于演示模型的文章,在WPF(前棱镜)的复合应用指南中有关于单独的演示模式的部分
MVC
Web框架通常使用,例如Laravel
,其中接收到的URL请求(可能由用户提出)由来处理,Controller
而生成的HTML View
发送给客户端-因此,View
属于后端和用户永远无法直接访问它,如果您遇到相反的情况,则可以将其视为MVC扩展(甚至违反)。@Panzercrisis,这不同于MVP
(和Android
OS 中使用的一样),在该环境中actions route through the View to the Presenter
,用户可以直接访问View
。
这是这些设计模式的许多变体的过度简化,但这就是我想考虑两者之间的差异的方式。
MVC
最有价值球员
不久前,我写了一篇关于这件事的博文,并引用了托德·斯奈德(Todd Snyder)的出色文章,介绍了两者之间的区别:
以下是这些模式之间的主要区别:
MVP模式
- 视图与模型之间的联系更加松散。演示者负责将模型绑定到视图。
- 单元测试更容易,因为与视图的交互是通过界面进行的
- 通常情况下,与演示者的地图是一对一的。复杂的视图可能有多个演示者。
MVC模式
- 控制器基于行为,可以在视图之间共享
- 可以负责确定要显示哪个视图
这是我在网上找到的最好的解释。
这是代表通信流程的插图
MVP是不是一定是这样一个场景,查看负责(见Taligent公司的例如MVP)。
我发现不幸的是,人们仍然将其作为一种模式(负责视图)而不是反模式来宣讲,因为它与“这只是一个视图”(实用程序员)相矛盾。“这只是一个视图”指出向用户显示的最终视图是该应用程序的第二要务。微软的MVP模式使视图的重用变得更加困难,并且为微软的设计师鼓励不良做法提供了便利。
坦率地说,我认为MVC的根本问题对于任何MVP实现都是正确的,并且差异几乎完全是语义上的。只要您遵循视图(显示数据),控制器(初始化和控制用户交互)和模型(基础数据和/或服务)之间的关注点分离,那么您就可以实现MVC的好处。如果您正在获得收益,那么谁真正在乎您的模式是MVC,MVP还是监督控制器?唯一的真实模式仍然是MVC,其余的只是它的不同风格。
考虑一下激动人心的文章,它全面列出了许多这些不同的实现。您可能会注意到,他们基本上都在做相同的事情,但略有不同。
我个人认为MVP只是在最近才重新引入,因为它可以减少在争论某些东西是否真正MVC的语义顽固派之间的争论,或者为证明Microsoft快速应用程序开发工具的合理性。在我的书中,这两个原因均不能证明其作为独立设计模式的存在。
在大多数情况下,视图会创建其演示者。演示者将与模型进行交互并通过界面操纵视图。视图有时通常会通过某些界面与演示者进行交互。这归结为实施;您是否希望视图调用演示者上的方法,还是希望视图具有演示者监听的事件?归结为:视图了解演示者。该视图委托给演示者。
控制器是根据某些事件/请求创建或访问的。控制器然后创建适当的视图,并与模型进行交互以进一步配置视图。归结为:控制器创建并管理视图;该视图是控制器的从属。该视图不了解控制器。
MVC(模型视图控制器)
输入首先指向控制器,而不是视图。该输入可能来自与页面交互的用户,但也可能来自简单地在浏览器中输入特定的URL。在任何一种情况下,其Controller都与之连接以启动某些功能。控制器和视图之间存在多对一的关系。这是因为单个控制器可以根据正在执行的操作选择要渲染的不同视图。请注意从控制器到视图的单向箭头。这是因为视图不了解控制器或对该控制器没有任何参考。Controller确实会传回模型,因此在View和传递给它的预期模型之间有知识,但Controller没有提供知识。
MVP(模型视图演示者)
输入从“视图”而不是“演示者”开始。视图和关联的Presenter之间存在一对一的映射。视图包含对演示者的引用。演示者还对从视图触发的事件做出反应,因此它知道与之关联的视图。演示者根据其在模型上执行的请求操作来更新视图,但是视图不支持模型。
更多参考
MVP
模式上,当应用程序第一次加载时,主持人不是负责加载第一个视图吗?例如,当我们加载facebook应用程序时,主持人是否不负责加载登录页面?
这个问题有很多答案,但是我觉得有必要将一些非常简单的答案清楚地比较两者。这是用户在MVP和MVC应用中搜索电影名称时所进行的讨论:
用户:单击单击…
视图:那是谁?[ MVP | MVC ]
用户:我只是点击了搜索按钮...
视图:好的,稍等片刻……。[ MVP | MVC ]
(查看呼叫Presenter | Controller的视图 …)[ MVP | MVC ]
查看:嘿演示 | 控制器,一个用户刚刚单击搜索按钮,我该怎么办?[ MVP | MVC ]
主持人 | 控制器:嘿查看,是否有任何网页上的搜索字词?[ MVP | MVC ]
视图:是的,这里是…“钢琴” [ MVP | MVC ]
主持人:感谢View,…同时我正在查找Model上的搜索字词,请向他/她显示进度条[ MVP | MVC ]
(演示者 | 控制器正在调用模型 …)[ MVP | MVC ]
主持人 | 管理员:嗨,模特儿,您对此搜索词有任何匹配吗?:“ piano” [ MVP | MVC ]
模特:嘿主持人 | 控制器,让我检查一下... [ MVP | MVC ]
(模型正在查询电影数据库…)[ MVP | MVC ]
( 过了一会儿 ... )
--------------这就是MVP和MVC开始分歧的地方---------------
模特:我为您找到了一个Presenter列表,在JSON中是“ [{{name”:“ Piano Teacher”,“ year”:2001},{“ name”:“ Piano”,“ year”:1993} ]” [ MVP ]
型号:Controller,有一些结果可用。我已经在实例中创建了一个字段变量,并用结果填充了它。它的名称是“ searchResultsList” [ MVC ]
(主持人 |控制器感谢模型并回到视图)[ MVP | MVC ]
演示者:感谢View的等待,我为您找到了匹配的结果列表,并以合适的格式排列它们:[“ Piano Teacher 2001”,“ Piano 1993”]。请在垂直列表中向用户显示。另外,请立即隐藏进度栏[ MVP ]
控制器:感谢您等待View,我已向Model询问您的搜索查询。它说已找到匹配结果的列表,并将它们存储在其实例内部的名为“ searchResultsList”的变量中。您可以从那里得到它。还请现在隐藏进度条[ MVC ]
视图:非常感谢主持人 [ MVP ]
视图:谢谢“控制器” [ MVC ](现在视图正在质疑自己:我应该如何展示从模型中获得的结果给用户?电影的制作年份是第一还是最后一年??是垂直列表还是水平列表?...)
如果您有兴趣,我已经撰写了一系列有关应用程序架构模式(MVC,MVP,MVVP,干净架构等)的文章,并附有Github回购 在这里。即使该示例是为android编写的,其基本原理也可以应用于任何媒介。
模型视图控制器
MVC是软件应用程序体系结构的一种模式。它将应用程序逻辑分为三个独立的部分,从而提高了模块性,并简化了协作和重用。它还使应用程序更加灵活并欢迎迭代,并将应用程序分为以下组件:
为了更清楚一点,让我们想象一个简单的购物清单应用程序。我们只需要列出本周需要购买的每件商品的名称,数量和价格。下面我们将描述如何使用MVC实现某些功能。
模型视图演示者
如果您想查看具有简单实现的示例,请查看 此 GitHub帖子
MVC和MVP模式之间有什么区别?
MVC模式
控制器基于行为,可以在视图之间共享
可以负责确定要显示的视图(前端控制器模式)
MVP模式
视图与模型之间的联系更加松散。演示者负责将模型绑定到视图。
单元测试更容易,因为与视图的交互是通过界面进行的
通常情况下,与演示者的地图是一对一的。复杂的视图可能有多个演示者。
还值得记住的是,MVP的类型也不同。Fowler将模式分为两种-被动视图和监督控制器。
使用被动视图时,视图通常会实现细粒度的界面,其属性或多或少直接映射到底层UI小部件。例如,您可能有一个具有名称和地址之类的ICustomerView的属性。
您的实现可能看起来像这样:
public class CustomerView : ICustomerView
{
public string Name
{
get { return txtName.Text; }
set { txtName.Text = value; }
}
}
Presenter类将与模型对话,并将其“映射”到视图。这种方法称为“被动视图”。好处是视图易于测试,并且在UI平台(Web,Windows / XAML等)之间移动也更容易。缺点是您不能利用数据绑定之类的东西(在WPF和Silverlight等框架中,它确实很强大)。
MVP的第二种形式是监督控制器。在这种情况下,您的视图可能具有一个名为Customer的属性,然后再次将其数据绑定到UI小部件。您不必考虑对视图进行同步和微管理,并且监督控制器可以在需要时介入并提供帮助,例如,使用强制的交互逻辑。
MVP的第三个“风味”(或者有人可能将其称为单独的模式)是Presentation Model(或有时称为Model-View-ViewModel)。与MVP相比,您将M和P“合并”到一个类别中。您的UI对象是数据绑定到的客户对象,但是您还具有其他特定于UI的字段,例如“ IsButtonEnabled”或“ IsReadOnly”等。
我认为,我发现有关UI体系结构的最佳资源是Jeremy Miller在“构建自己的CAB系列目录”中撰写的一系列博客文章。。他介绍了MVP的所有方面,并展示了实现它们的C#代码。
在YouCard重新访问的时候,我还在 Silverlight的上下文中写了有关Model-View-ViewModel模式的博客:重新实现了ViewModel模式。
它们各自解决不同的问题,甚至可以组合在一起形成如下所示的内容
这两个框架的目的都是分开关注,例如,与数据源(模型)的交互,应用程序逻辑(或将这些数据转换为有用的信息)(控制器/演示器)和显示代码(视图)。在某些情况下,该模型还可以用于将数据源转换为更高级别的抽象。MVC Storefront项目就是一个很好的例子。
有一个讨论,这里就VS MVP MVC之间的差异。
所做出的区别是,在MVC应用程序中,传统上具有视图,并且控制器与模型交互,但彼此不交互。
MVP设计使Presenter访问模型并与视图交互。
话虽如此,ASP.NET MVC通过这些定义是一个MVP框架,因为控制器访问模型以填充视图,而该视图本来是没有逻辑的(仅显示控制器提供的变量)。
要了解MVP与ASP.NET MVC的区别,请查看Scott Hanselman的MIX演示。
两者都是试图将表示和业务逻辑分离,将业务逻辑与UI方面分离的模式
在架构上,MVP是基于页面控制器的方法,而MVC是基于前端控制器的方法。这意味着在MVP标准Web表单页面中,生命周期只是通过从后面的代码中提取业务逻辑来增强。换句话说,page是服务http请求的请求。换句话说,MVP IMHO是Web表单进化类型的增强功能。另一方面,MVC完全改变了游戏,因为在页面加载之前,请求类被控制器类拦截,在那里执行业务逻辑,然后在控制器处理刚转储到页面的数据(“视图”)的最终结果中从某种意义上说,MVC(至少对我而言)对路由引擎增强的MVP的Supervising Controller风格很有帮助
他们俩都支持TDD,并且有缺点和缺点。
如何选择其中一个恕我直言的决定应基于一个人在ASP NET Web表单类型的Web开发上投入了多少时间。如果有人认为自己擅长于Web表单,我建议MVP。如果人们对页面生命周期之类的事情不太满意,那么MVC可能是解决问题的一种方法。
这是另一个博客文章链接,提供有关此主题的更多详细信息
我曾经使用过MVP和MVC,尽管我们(作为开发人员)倾向于关注两种模式的技术差异,但恕我直言,MHO中MVP的意义与易用性息息相关。
如果我正在一个已经具有Web表单开发风格的良好背景的团队中工作,那么介绍MVP比MVC要容易得多。我想说,在这种情况下,MVP是一个快速的胜利。
我的经验告诉我,将团队从Web表单迁移到MVP,然后从MVP迁移到MVC相对容易。从Web表单迁移到MVC更加困难。
我在这里留下指向我的一个朋友发表的有关MVP和MVC的系列文章的链接。
http://www.qsoft.be/post/Building-the-MVP-StoreFront-Gutthrie-style.aspx
在MVP中,视图从演示者中提取数据,演示者从模型中提取数据并对其进行准备/归一化;而在MVC中,控制器通过推入视图从模型中进行数据设置。
在MVP中,您可以具有一个与多种类型的演示者一起使用的视图,以及一个与不同的多种视图一起使用的演示者。
MVP通常使用某种绑定框架,例如Microsoft WPF绑定框架或用于HTML5和Java的各种绑定框架。
在这些框架中,UI / HTML5 / XAML知道每个UI元素显示的演示者的属性,因此,当您将视图绑定到演示者时,视图将查找属性,并且知道如何从它们中绘制数据以及如何在用户更改UI中的值时进行设置。
因此,例如,如果模型是一辆汽车,那么演示者就是某种汽车演示者,将汽车属性(年份,制造商,座位等)暴露给视图。该视图知道称为“汽车制造商”的文本字段需要显示Presenter Maker属性。
然后,您可以将许多不同类型的演示者绑定到视图,所有演示者都必须具有Maker属性-它可以是飞机,火车或其他任何东西,该视图无关紧要。只要实现了约定的界面,该视图就会从演示者那里获取数据-无论哪种方式。
这个绑定框架,如果将其剥离,实际上是控制器:-)
因此,您可以将MVP视为MVC的演进。
MVC很棒,但是问题在于通常每个视图都有它的控制器。控制器A知道如何设置视图A的字段。如果现在,您希望视图A显示模型B的数据,则需要控制器A知道模型B,或者需要控制器A接收带有接口的对象-就像仅MVP不带绑定,否则您需要在Controller B中重写UI设置代码。
结论-MVP和MVC都是UI模式的分离,但MVP通常使用下面的MVC绑定框架。THUS MVP的体系结构级别高于MVC,并且其包装模式高于MVC。
MVC有很多版本,此答案与Smalltalk中的原始MVC有关。简而言之,它是
这篇演讲droidcon NYC 2017-使用Architecture Components进行的干净应用程序设计澄清了它
UIKit
有这种从Bob大叔不错的视频,他简要介绍了MVC&MVP底。
IMO,MVP是MVC的改进版本,您基本上可以将要显示的内容(数据)与要显示的内容(视图)分开。演示者包括您的UI的业务逻辑,隐式强加了应显示的数据,并为您提供了一个哑视图模型列表。而且,当需要显示数据时,您只需将视图(可能包括相同的ID)插入适配器,并使用引入最少代码(仅使用setter)的那些视图模型来设置相关视图字段。它的主要好处是您可以针对许多/各种视图(例如,在水平列表或垂直列表中显示项目)测试UI业务逻辑。
在MVC中,我们通过接口(边界)进行对话以粘合不同的层。控制器是我们架构的一个插件,但是它并没有施加任何限制。从这个意义上讲,MVP是一种MVC,其概念是可通过适配器将视图插入控制器。
我希望这会有所帮助。
您忘记了动作域响应器(ADR)。
如上图所示,MVC中的模型与视图之间存在直接关系/链接。在Controller上执行一个动作,该Controller将在Model上执行一个动作。在这一行动模式,将触发反应的视图。该视图的时候总是更新型号的状态发生改变。
有些人忘记了MVC 是在70年代后期创建的,而Web只在80英寸/ 90年代初创建的。MVC最初不是为Web创建的,而是为桌面应用程序创建的,而Controller是,模型和视图将并存。
因为我们使用的Web框架(例如:。Laravel)仍然使用相同的命名约定(model-view-controller),所以我们倾向于认为它必须是MVC,但实际上是其他东西。
相反,请查看Action-Domain-Responder。在ADR中,控制器获得一个Action,它将在Model / Domain中执行操作。到目前为止,都一样。不同之处在于,它随后收集了该操作的响应/数据,并将其传递给Responder(例如:)view()
进行渲染。当在同一组件上请求执行新操作时,将再次调用Controller,然后循环重复进行。在ADR中,模型/域与视图(响应者的响应)之间没有联系。
注意: Wikipedia指出“ 但是,每个ADR操作均由单独的类或闭包表示。 ”。这是不完全正确。多个动作可以在同一Controller中,并且模式仍然相同。
最简单的答案是视图如何与模型交互。在MVP中,视图由演示者更新,该演示者充当视图和模型之间的中介。演示者从视图中获取输入,该视图从模型中检索数据,然后执行所需的任何业务逻辑,然后更新视图。在MVC中,模型直接更新视图,而不是通过控制器返回。
最有价值球员
MVP代表模型-视图呈现器。这是2007年初的一张照片,Microsoft引入了Smart Client Windows应用程序。
演示者在MVP中充当监督角色,该MVP绑定了View事件和模型中的业务逻辑。
视图事件绑定将通过视图界面在Presenter中实现。
该视图是用户输入的发起者,然后将事件委托给Presenter,presenter处理事件绑定并从模型获取数据。
优点: 视图仅具有UI,没有任何逻辑高可测试性
缺点: 实现事件绑定时有点复杂并且工作更多
MVC
MVC代表模型-视图-控制器。Controller负责创建模型并使用绑定模型渲染视图。
控制器是发起者,它决定渲染哪个视图。
优点: 强调单一责任原则高水平的可测试性
缺点: 如果尝试在同一控制器中呈现多个视图,则有时对于Controllers来说工作量过多。