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

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


当前回答

鲍勃叔叔的这段视频很好,他在最后简要解释了MVC和MVP。

IMO,MVP是MVC的一个改进版本,基本上可以将你要显示的内容(数据)与你要显示(视图)的方式分开。演示者包含了UI的某种业务逻辑,隐式地规定了应该显示哪些数据,并为您提供了一个哑视图模型列表。当显示数据时,只需将视图(可能包含相同的id)插入适配器,并使用这些视图模型设置相关的视图字段,只需引入最少的代码(仅使用setter)。它的主要好处是您可以针对许多/各种视图测试UI业务逻辑,例如在水平列表或垂直列表中显示项目。

在MVC中,我们通过接口(边界)来粘合不同的层。控制器是我们体系结构的一个插件,但它对显示内容没有任何限制。从这个意义上讲,MVP是一种MVC,其概念是视图可以通过适配器插入控制器。

我希望这有助于更好。

其他回答

同样值得记住的是,MVP也有不同的类型。福勒将这种模式分为两种:被动视图和监督控制器。

使用被动视图时,视图通常实现一个细粒度的接口,其中财产或多或少直接映射到底层UI小部件。例如,您可能有一个具有诸如Name和Address等财产的ICustomerView。

您的实现可能如下所示:

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

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

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

MVP的第三个“味道”(或者有人可能会称之为一个单独的模式)是演示模型(或者有时称为模型-视图-视图模型)。与MVP相比,你将M和P“合并”为一个类。您有UI小部件数据绑定到的客户对象,但也有其他UI特定字段,如“IsButtonEnabled”或“IsReadOnly”等。

我认为我找到的最好的UI架构资源是Jeremy Miller在the Build Your Own CAB系列目录上发表的一系列博客文章。他涵盖了MVP的所有风格,并展示了实现它们的C#代码。

我也在YouCard网站上写过关于Silverlight上下文中的模型-视图-视图-模型模式的博客。

表示器

在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适用于小范围。有了MVC,我有时会觉得V和C可能被看作是一个不可分割的组件的两面,而不是直接绑定到M,当向下扩展到较短的规模时,如UI控件和基本控件时,必然会出现这种情况。在这种粒度级别上,MVP意义不大。相反,当一个人走向更大的规模时,适当的界面变得更重要,同样,明确的职责分配也同样重要,MVP就来了。

另一方面,当平台特性有助于组件之间的某种关系时,例如在web上,MVC的实现似乎比MVP更容易。

我已经使用了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

MVP:观点是主导的。

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

MVC:控制器负责。

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