当超越RAD(拖放和配置)构建用户界面的方式时,许多工具鼓励你可能遇到三种设计模式,称为Model-View-Controller,Model-View-Presenter和Model-View-ViewModel。我的问题有三个部分:
在MVP中,Presenter包含View的UI业务逻辑。 View中的所有调用都直接委托给Presenter。 Presenter也直接与View分离,并通过界面与之对话。这是为了允许在单元测试中模拟View。 MVP的一个常见属性是必须进行大量的双向调度。例如,当有人单击“保存”按钮时,事件处理程序将委托给Presenter的“OnSave”方法。保存完成后,Presenter将通过其界面回调View,以便View可以显示保存已完成。
MVP往往是在Web窗体中实现单独呈现的非常自然的模式。原因是View总是首先由ASP.NET运行时创建。你可以find out more about both variants。
被动视图:视图尽可能愚蠢,几乎没有逻辑。演示者是一个与视图和模型对话的中间人。视图和模型完全相互屏蔽。模型可能会引发事件,但Presenter会订阅它们以更新视图。在被动视图中没有直接数据绑定,而是View公开了Presenter用于设置数据的setter属性。所有状态都在Presenter中管理,而不是View。
监督控制器:演示者处理用户手势。 View直接通过数据绑定绑定到Model。在这种情况下,Presenter的工作是将Model传递给View,以便它可以绑定到它。演示者还将包含手势逻辑,如按下按钮,导航等。
在MVC中,Controller负责确定显示哪个View以响应任何操作,包括何时加载应用程序。这与MVP不同,其中操作通过View路由到Presenter。在MVC中,View中的每个操作都与对Controller的调用以及操作相关联。在网络中,每个动作都涉及对URL的调用,在URL的另一侧有一个Controller响应。控制器完成处理后,将返回正确的视图。在整个应用程序的生命周期中,序列以这种方式继续:
Action in the View -> Call to Controller -> Controller Logic -> Controller returns the View.
MVC的另一个重要区别是View不直接绑定到Model。视图简单地呈现,并且完全是无状态的。在MVC的实现中,View通常不会在后面的代码中有任何逻辑。这与MVP完全相反,因为如果View没有委托给Presenter,它将永远不会被调用。
要看的另一种模式是Presentation Model模式。在这种模式中没有Presenter。相反,View直接绑定到Presentation Model。 Presentation Model是专为View设计的模型。这意味着此模型可以公开一个永远不会放在域模型上的属性,因为它会违反关注点分离。在这种情况下,表示模型绑定到域模型,并可以订阅来自该模型的事件。 View然后订阅来自Presentation Model的事件并相应地更新自身。表示模型可以公开视图用于调用操作的命令。这种方法的优点在于,您可以完全删除代码隐藏,因为PM完全封装了视图的所有行为。这种模式非常适合在WPF应用程序中使用,也称为Model-View-ViewModel。
有一个MSDN article about the Presentation Model和Composite Application Guidance for WPF(前棱镜)关于Separated Presentation Patterns的一个部分
另外值得记住的是,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在The Build Your Own CAB Series Table of Contents上完成的一系列博客文章。他涵盖了MVP的所有风格,并展示了C#代码来实现它们。
我还在YouCard Re-visited: Implementing the ViewModel pattern的Silverlight上下文中讨论了Model-View-ViewModel模式。
模型 - 视图 - 控制器
MVC是软件应用程序体系结构的模式。它将应用程序逻辑分为三个独立的部分,促进了模块化,易于协作和重用。它还使应用程序更灵活,更欢迎迭代。它将应用程序分为以下组件:
为了使这一点更加清晰,让我们设想一个简单的购物清单应用程序。我们想要的只是我们本周需要购买的每件商品的名称,数量和价格清单。下面我们将描述如何使用MVC实现某些功能。
模型 - 视图 - 演示
如果您想查看简单实现的示例,请查看this GitHub帖子
MVC和MVP模式有什么区别?
MVC模式
MVP模式
它们各自解决了不同的问题,甚至可以组合在一起,形成如下所示的东西
这两个框架都旨在分离关注点 - 例如,与数据源(模型)的交互,应用程序逻辑(或将此数据转换为有用信息)(Controller / Presenter)和显示代码(View)。在某些情况下,模型也可用于将数据源转换为更高级别的抽象。一个很好的例子是MVC Storefront project。
有关MVC与MVP之间差异的讨论here。
区别在于,MVC应用程序传统上具有视图,并且控制器与模型交互,但彼此不交互。
MVP设计让Presenter访问模型并与视图交互。
话虽如此,ASP.NET MVC通过这些定义是一个MVP框架,因为Controller访问模型来填充View,这意味着没有逻辑(只显示Controller提供的变量)。
要想了解ASP.NET MVC与MVP的区别,请查看Scott Hanselman撰写的this MIX presentation。
两者都是试图将表示和业务逻辑分开,将业务逻辑与UI方面分离的模式
在架构上,MVP是基于页面控制器的方法,其中MVC是基于前端控制器的方法。这意味着在MVP标准Web表单中,页面生命周期只是通过从后面的代码中提取业务逻辑来增强。换句话说,页面是服务http请求的页面。换句话说,MVP恕我直言是网络形式的进化类型的增强。 MVC另一方面完全改变了游戏,因为在加载页面之前,控制器类拦截了请求,在那里执行了业务逻辑,然后在控制器处理刚刚转储到页面的数据(“view”)的最终结果中感觉,MVC对于使用路由引擎增强的MVP的监督控制器风格看起来(至少对我而言)很多
它们都能实现TDD并具有缺点和优势。
关于如何选择其中一个的决定恕我直言应该基于投入ASP NET网络表单类型的Web开发的时间。如果一个人认为自己在网络形式上很好,我会建议MVP。如果在页面生命周期等事情上感觉不太舒服,MVC可能是一种方法。
这是另一个博客文章链接,提供了有关此主题的更多详细信息
我已经使用了MVP和MVC,虽然我们作为开发人员倾向于关注两种模式的技术差异,但恕我直言中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中更改值时设置它们。
因此,例如,如果模型是汽车,则演示者是某种汽车演示者,将汽车属性(年份,制造商,座位等)暴露给视图。该视图知道名为“car maker”的文本字段需要显示演示者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之上的包装模式。
我简陋的短视图:MVP适用于大尺度,而MVC适用于小尺度。对于MVC,我有时会觉得V和C可能被看作是单个不可分割组件的两个而不是直接绑定到M,并且当向下到较短的比例时,一个不可避免地会出现这种情况,比如UI控件和基本小部件。在这种粒度级别上,MVP毫无意义。相反,当一个人进入更大的规模时,适当的界面变得更加重要,同样明确的责任分配,这就是MVP。
另一方面,当平台特征有利于组件之间的某种关系时,拇指的这种缩放规则可能非常小,例如与Web相比,它似乎更容易实现MVC,而不是MVP。
有许多版本的MVC,这个答案是关于Smalltalk中的原始MVC。简而言之,它是
这次谈话droidcon NYC 2017 - Clean app design with Architecture Components澄清了它
来自鲍勃叔叔的this精彩视频,他最后简要介绍了MVC和MVP。
IMO,MVP是MVC的改进版本,您基本上将您要展示的内容(数据)与您将要展示的内容(视图)区分开来。 Presenter包含了UI的业务逻辑,隐含地强加了应该呈现的数据,并为您提供了一个哑视图模型列表。当显示数据时,您只需将视图(可能包含相同的ID)插入适配器,并使用这些视图模型设置相关的视图字段,并引入最少量的代码(仅使用setter)。它的主要好处是您可以针对许多/不同的视图测试UI业务逻辑,例如在水平列表或垂直列表中显示项目。
在MVC中,我们通过接口(边界)来讨论粘合不同的层。控制器是我们架构的一个插件,但它没有限制强加什么显示。从这个意义上说,MVP是一种MVC,其概念可以通过适配器插入控制器。
希望这会有所帮助。
这是对这些设计模式的许多变体的过度简化,但这就是我喜欢考虑两者之间差异的方式。
MVC
MVP
最简单的答案是视图如何与模型交互。在MVP中,视图绑定到演示者,演示者充当视图和模型之间的中介,从视图获取输入,从模型获取数据,然后执行业务逻辑并最终更新视图。在MVC中,模型直接更新视图,而不是通过控制器返回。
MVP
MVP代表Model - View-Presenter。 2007年初,微软推出了Smart Client Windows应用程序。
Presenter充当MVP中的监督角色,它从模型中绑定View事件和业务逻辑。
视图事件绑定将在视图界面中在Presenter中实现。
View是用户输入的发起者,然后将事件委托给Presenter,演示者处理事件绑定并从模型中获取数据。
优点:View只有UI而不是任何逻辑高可测性
缺点:实现事件绑定时,位置复杂且工作量更大
MVC
MVC代表模型 - 视图 - 控制器。 Controller负责使用绑定模型创建模型和渲染视图。
Controller是发起者,它决定渲染哪个视图。
优点:强调单一责任原则高水平的可测试性
缺点:如果尝试在同一个控制器中渲染多个视图,有时控制器的工作负载太多。
我在一段时间后在博客上发帖,引用Todd Snyder's excellent post on the difference between the two:
以下是模式之间的主要区别:
MVP模式
- 视图与模型的关系更松散。演示者负责将模型绑定到视图。
- 更容易进行单元测试,因为与视图的交互是通过接口进行的
- 通常一对一地查看演示者地图。复杂视图可能有多个演示者。
MVC模式
- 控制器基于行为,可以跨视图共享
- 可以负责确定要显示的视图
这是我能找到的网上最好的解释。
以下是代表通信流程的插图
MVP不一定是View负责的场景(例如,参见Taligent的MVP)。 我发现不幸的是,人们仍在宣传这种模式(负责观点),而不是反模式,因为它与“它只是一种观点”(实用程序员)相矛盾。 “这仅仅是一种观点”指出向用户显示的最终视图是应用程序的次要问题。微软的MVP模式使得重复使用Views变得更加困难,并且方便了微软的设计师鼓励不良做法。
坦率地说,我认为MVC的潜在问题适用于任何MVP实现,差异几乎完全是语义的。只要您关注视图(显示数据),控制器(初始化和控制用户交互)和模型(基础数据和/或服务)之间的关注点分离,那么您就可以实现MVC的优势。如果您正在获得好处,那么谁真正关心您的模式是MVC,MVP还是监督控制器?唯一真实的模式仍然是MVC,其余的只是不同的风格。
考虑this非常令人兴奋的文章,它全面列出了许多这些不同的实现。您可能会注意到,他们基本上都在做同样的事情,但略有不同。
我个人认为MVP最近才被重新引入作为一个吸引人的术语,要么减少语义偏执者之间的争论,他们争论某些东西是否真的是MVC,或者证明微软快速应用程序开发工具的合理性。在我的书中,这些原因都不能证明它作为一种单独的设计模式存在。
在大多数情况下,视图会创建其演示者。演示者将与模型交互并通过界面操纵视图。视图有时会通过某种界面与演示者进行交互。这归结为实施;您希望视图在演示者上调用方法,还是希望视图具有演示者侦听的事件?它归结为:视图了解演示者。视图委托给演示者。
根据某些事件/请求创建或访问控制器。然后,控制器创建适当的视图并与模型交互以进一步配置视图。它归结为:控制器创建和管理视图;视图是控制器的从属。视图不知道控制器。
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。
这个问题有很多答案,但我觉得需要一些非常简单的答案,清楚地比较两者。以下是用户在MVP和MVC应用中搜索电影名称时所做的讨论:
用户:点击点击...
观点:那是谁? [MVP | MVC]
用户:我刚刚点击了搜索按钮......
查看:好的,等一下...... [MVP | MVC]
(查看调用Presenter | Controller ...)[MVP | MVC]
查看:嗨Presenter |控制器,用户刚刚点击搜索按钮,我该怎么办? [MVP | MVC]
演示者|控制器:嘿View,该页面上是否有搜索词? [MVP | MVC]
观点:是的,......这里是......“钢琴”[MVP | MVC]
主持人:谢谢观看,...同时我正在查找模型上的搜索词,请向他/她显示进度条[MVP | MVC]
(Presenter | Controller正在调用Model ...)[MVP | MVC]
主持人|控制器:Hey Model,这个搜索字词是否匹配?:“piano”[MVP | MVC]
型号:Hey Presenter |控制器,让我查一下...... [MVP | MVC]
(模型正在对电影数据库进行查询......)[MVP | MVC]
( 过了一会儿 ... )
--------------这就是MVP和MVC开始分歧的地方---------------
型号:我为你找到了一个列表,Presenter,这里是JSON“[{”name“:”Piano Teacher“,”year“:2001},{”name“:”Piano“,”year“:1993} ]“[MVP]
型号:有一些结果可用,控制器。我在我的实例中创建了一个字段变量,并用结果填充它。它的名字是“searchResultsList”[MVC]
(演示者|控制器感谢模型并返回视图)[MVP | MVC]
主持人:感谢等待观看,我找到了一份匹配结果列表,并以一种可呈现的格式排列:[“Piano Teacher 2001”,“Piano 1993”]。请在垂直列表中向用户显示。也请现在隐藏进度条[MVP]
控制器:感谢您等待View,我向Model询问了您的搜索查询。它说它找到了一个匹配结果列表,并将它们存储在其实例中名为“searchResultsList”的变量中。你可以从那里得到它。也请现在隐藏进度条[MVC]
观点:非常感谢Presenter [MVP]
查看:谢谢“控制器”[MVC](现在视图正在质疑:我应该如何呈现从模型中获得的结果给用户?电影的制作年份应该是第一个还是最后一个......?应该是在垂直或水平列表?...)
如果您感兴趣,我一直在撰写一系列文章,涉及应用程序架构模式(MVC,MVP,MVVP,清洁架构......)以及Github repo here。尽管该示例是为Android编写的,但基本原则可以应用于任何介质。