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

这些模式解决了什么问题?它们有什么相似之处?它们有何不同?


当前回答

我已经使用了MVP和MVC,尽管我们作为开发人员倾向于关注这两种模式的技术差异,但IMHO中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

其他回答

这两种模式都试图分离表示和业务逻辑,将业务逻辑与UI方面分离

在架构上,MVP是基于页面控制器的方法,而MVC是基于前端控制器的方法。这意味着MVP标准的web表单页面生命周期只是通过从代码后面提取业务逻辑来增强的。换句话说,page是为http请求提供服务的页面。换句话说,MVP IMHO是一种网络形式的进化型增强。另一方面,MVC完全改变了游戏,因为在加载页面之前,请求被控制器类拦截,在那里执行业务逻辑,然后在控制器处理刚刚转储到页面的数据的最终结果(“视图”)从这个意义上讲,MVC看起来(至少在我看来)很像MVP的Supervisory Controller风格,它通过路由引擎增强了MVP的功能

这两种方法都支持TDD,并有其优缺点。

关于如何选择其中一个IMHO的决定应该基于在ASP.NET web表单类型的web开发中投入的时间。如果有人认为自己擅长网络形式,我会建议MVP。如果你在页面生命周期等方面感觉不太舒服的话,MVC可能是一种方法。

下面是另一个博客文章链接,提供了关于这个主题的更多细节

http://blog.vuscode.com/malovicn/archive/2007/12/18/model-view-presenter-mvp-vs-model-view-controller-mvc.aspx

你忘了动作域响应程序(ADR)。

正如上面的一些图形所解释的,MVC中的模型和视图之间有直接的关系/链接。在控制器上执行操作,控制器将在模型上执行操作。模型中的该操作将触发视图中的反应。视图在模型状态更改时始终更新。

有些人一直忘记了,MVC是在70年代末创建的,而Web只是在80年代末/90年代初创建的。MVC最初不是为Web创建的,而是为桌面应用程序创建的,其中Controller、Model和View将共存。

因为我们使用的是仍然使用相同命名约定(模型-视图-控制器)的web框架(例如:.Laravel),所以我们倾向于认为它必须是MVC,但实际上是其他东西。

相反,请查看操作域响应程序。在ADR中,控制器获得一个动作,该动作将在模型/域中执行操作。到目前为止,情况是一样的。不同的是,它然后收集该操作的响应/数据,并将其传递给Responder(例如:.view())进行渲染。当在同一组件上请求新操作时,将再次调用Controller,并重复循环。在ADR中,模型/域和视图(Reposer的响应)之间没有任何联系。

注意:维基百科指出“然而,每个ADR动作都由单独的类或闭包表示”。这不一定是真的。多个操作可以在同一控制器中,并且模式仍然相同。

mvc adr模型视图控制器动作域响应器

模型视图控制器

MVC是软件应用程序架构的一种模式。它将应用程序逻辑分为三个独立的部分,促进了模块化和易于协作和重用。它还使应用程序更灵活,更易于迭代。它将应用程序分为以下组件:

处理数据和业务逻辑的模型用于处理用户界面和应用程序的控制器用于处理图形用户界面对象和演示的视图

为了更清楚一点,让我们想象一个简单的购物清单应用程序。我们只需要一份本周需要购买的每件商品的名称、数量和价格的清单。下面我们将描述如何使用MVC实现这些功能。

表示器

模型是将在视图(用户界面)中显示的数据。该视图是一个界面,它显示数据(模型)并将用户命令(事件)发送给演示者,以根据该数据进行操作。视图通常引用其演示者。演示者是“中间人”(由MVC中的控制器扮演),并同时引用视图和模型。请注意,“模型”一词具有误导性。它应该是检索或操纵模型的业务逻辑。例如:如果您有一个数据库将User存储在数据库表中,并且您的View希望显示用户列表,那么Presenter将具有对数据库业务逻辑(如DAO)的引用,Presenter将从中查询用户列表。

如果您想查看具有简单实现的示例,请检查此GitHub帖子

从数据库中查询和显示用户列表的具体工作流可以如下所示:

MVC模式和MVP模式有什么区别?

MVC模式

控制器基于行为,可以跨视图共享可以负责确定要显示的视图(前控制器模式)

MVP模式

视图与模型的耦合更加松散。演示者负责将模型绑定到视图。更容易进行单元测试,因为与视图的交互是通过接口进行的通常视图到演示者的映射是一对一。复杂视图可能有多个演示者。

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

用户:单击…

观点:那是谁?[MVP|MVC]

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

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

(视图调用演示者|控制器…)[MMVP|MVC]

视图:嗨,演示者|控制器,用户刚刚单击了搜索按钮,我该怎么办?[MVP|MVC]

演示者|控制器:嘿,View,那个页面上有搜索词吗?[MVP|MVC]

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

演示者|控制器:谢谢查看,……同时我正在查找模型上的搜索项,请向他/她显示进度条[MVP|MVC]

(演示者|控制器正在调用模型…)[MMVP|MVC]

演示者|控制器:嘿,模特儿,你有匹配这个搜索词的吗?:“钢琴”[MVP|MVC]

模型:嘿,演示者|控制器,让我检查一下…〔MVP|MVC〕

(模型正在对电影数据库进行查询…)[MVP|MVC]

(过了一会儿…)

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

模型:我为您找到了一个列表,演示者,这里是JSON格式的“[{“name”:“Piano Teacher”,“year”:2001},{“name:”Piano”,“year”:1993}]”[MVP]

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

(演示者|控制器感谢模型并返回视图)[MMVP|MVC]

演示者:感谢等待View,我为您找到了一个匹配结果列表,并以可呈现的格式排列:[“Piano Teacher 2001”,“Piano 1993”]。请在垂直列表中向用户显示。也请现在隐藏进度条[MMVP]

控制器:感谢等待View,我已经向Model询问了您的搜索查询。它说它找到了一个匹配结果的列表,并将它们存储在其实例中名为“searchResultsList”的变量中。你可以从那里得到它。也请立即隐藏进度条[MVC]

观点:非常感谢演示者MVP

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

如果你感兴趣的话,我一直在写一系列关于应用程序架构模式(MVC、MVP、MVVP、干净架构……)的文章,并在这里附上Github repo。尽管该示例是为android编写的,但其基本原理可以应用于任何介质。

表示器

在MVP中,演示者包含视图的UI业务逻辑。视图中的所有调用都直接委派给演示者。演示者也直接与视图分离,并通过接口与视图对话。这是为了允许在单元测试中模拟视图。MVP的一个共同特点是必须有很多双向调度。例如,当有人单击“保存”按钮时,事件处理程序将委托给演示者的“OnSave”方法。保存完成后,演示者将通过其界面调用视图,以便视图显示保存已完成。

MVP往往是在WebForms中实现分离表示的一种非常自然的模式。原因是视图总是首先由ASP.NET运行时创建。您可以了解更多关于这两种变体的信息。

两种主要变化

被动视图:视图尽可能地哑,几乎包含零逻辑。演示者是与视图和模型对话的中间人。视图和模型彼此完全屏蔽。模型可能会引发事件,但演示者会订阅这些事件以更新视图。在被动视图中,没有直接的数据绑定,相反,视图公开了演示者用于设置数据的setter财产。所有状态都在演示者中管理,而不是在视图中管理。

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

监督控制器:演示者处理用户手势。视图通过数据绑定直接绑定到模型。在这种情况下,演示者的工作是将模型传递给视图,以便它可以绑定到它。演示者还将包含诸如按下按钮、导航等手势的逻辑。

优点:通过利用数据绑定,减少了代码量。缺点:有一个不太可测试的表面(因为数据绑定),并且视图中的封装更少,因为它直接与模型对话。

模型视图控制器

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

    Action in the View
        -> Call to Controller
        -> Controller Logic
        -> Controller returns the View.

MVC的另一个重要区别是视图不直接绑定到模型。该视图只是呈现,完全无状态。在MVC的实现中,视图通常在代码后面没有任何逻辑。这与MVP相反,MVP是绝对必要的,因为如果视图不委托给演示者,它将永远不会被调用。

演示模型

另一种模式是演示模型模式。在此模式中,没有演示者。相反,视图直接绑定到演示模型。演示模型是专门为视图设计的模型。这意味着该模型可以公开人们永远不会放在域模型上的财产,因为这将违反关注分离。在这种情况下,表示模型绑定到域模型,并可以订阅来自该模型的事件。然后,视图订阅来自演示模型的事件,并相应地更新自己。表示模型可以公开视图用于调用操作的命令。这种方法的优点是,当PM完全封装了视图的所有行为时,您基本上可以完全删除代码。这种模式非常适合在WPF应用程序中使用,也称为模型视图视图模型。

MSDN上有一篇关于演示模型的文章,WPF(前Prism)的复合应用指南中有一节关于分离的演示模式