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

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


当前回答

表示器

在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)的复合应用指南中有一节关于分离的演示模式

其他回答

表示器

在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)的复合应用指南中有一节关于分离的演示模式

最简单的答案是视图如何与模型交互。在MVP中,视图由演示者更新,演示者充当视图和模型之间的中介。演示者从视图中获取输入,视图从模型中检索数据,然后执行所需的任何业务逻辑,然后更新视图。在MVC中,模型直接更新视图,而不是通过控制器返回。

MVP

MVP代表模型-视图-演示者。2007年初,微软推出了Smart Client windows应用程序。

演示者在MVP中充当监督角色,MVP绑定模型中的视图事件和业务逻辑。

视图事件绑定将从视图界面在Presenter中实现。

视图是用户输入的发起者,然后将事件委派给演示者,演示者处理事件绑定并从模型中获取数据。

赞成的意见:视图只有UI,没有任何逻辑高水平的可测试性

欺骗:实现事件绑定时有点复杂,工作量更大

MVC

MVC代表模型视图控制器。控制器负责创建模型并使用绑定模型渲染视图。

控制器是启动器,它决定渲染哪个视图。

赞成的意见:强调单一责任原则高水平的可测试性

欺骗:如果试图在同一控制器中渲染多个视图,有时控制器的工作量太大。

这个问题有很多答案,但我觉得需要一些非常简单的答案来清楚地比较两者。以下是我在用户在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编写的,但其基本原理可以应用于任何介质。

模型视图控制器

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

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

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

表示器

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

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

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

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

MVC模式

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

MVP模式

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