关于设计模式:什么是MVP和MVC,有什么区别?

What are MVP and MVC and what is the difference?

当你超越雷达(拖曳和配置)时,许多工具鼓励你的用户界面,你可以跨越三个设计模式,称为模型-视图控制器,模型-视图-视图-视图-视图模型。我的问题有三个方面:

  • 这些模式的地址是什么问题?
  • 他们是怎么相似的?
  • 他们有什么不同?

  • 表示器

    在MVP中,演示者包含视图的UI业务逻辑。视图中的所有调用都直接委托给演示者。演示者还可以直接从视图中分离出来,并通过接口与之对话。这允许在单元测试中模拟视图。MVP的一个常见属性是必须有大量的双向调度。例如,当有人单击"保存"按钮时,事件处理程序将委托给演示者的"onsave"方法。保存完成后,演示者将通过其界面调用视图,以便视图显示保存已完成。好的。

    MVP往往是实现Web表单中独立表示的一种非常自然的模式。原因是视图总是首先由ASP.NET运行时创建。您可以了解更多关于这两种变体的信息。好的。两个主要变化

    被动视图:视图尽可能地哑,包含几乎为零的逻辑。演讲者是一个与观点和模型对话的中间人。视图和模型完全相互屏蔽。模型可能会引发事件,但演示者订阅它们以更新视图。在被动视图中,没有直接的数据绑定,相反,视图公开了演示者用来设置数据的setter属性。所有状态都在演示者而不是视图中管理。好的。

    • pro:最大可测试性表面;视图和模型的清晰分离
    • con:更多的工作(例如所有setter属性)就像您自己做所有数据绑定一样。

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

    • pro:通过利用数据绑定,减少了代码量。
    • con:由于数据绑定,测试面更少,视图中的封装也更少,因为它直接与模型对话。

    模型视图控制器

    在MVC中,控制器负责确定响应任何操作(包括加载应用程序时)显示的视图。这与MVP不同,MVP中的操作通过视图路由到演示者。在MVC中,视图中的每个操作都与对控制器的调用以及操作相关。在Web中,每个操作都涉及到对另一侧的URL的调用,其中有一个控制器负责响应。一旦控制器完成其处理,它将返回正确的视图。在应用程序的整个生命周期中,该序列以这种方式继续:好的。

    1
    2
    3
    4
        Action in the View
            -> Call to Controller
            -> Controller Logic
            -> Controller returns the View.

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

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

    有一篇关于表示模型的msdn文章,以及WPF(前prism)的复合应用指南中关于分离表示模式的一节。好的。好啊。


    这是对这些设计模式的许多变体的过度简化,但这是我喜欢思考这两者之间的区别的方式。

    MVC

    MVC

    最有价值球员

    enter image description here


    不久前,我在博客上引用了托德·斯奈德关于这两者之间区别的优秀文章:

    Here are the key differences between
    the patterns:

    MVP Pattern

    • View is more loosely coupled to the model. The presenter is
      responsible for binding the model to
      the view.
    • Easier to unit test because interaction with the view is through
      an interface
    • Usually view to presenter map one to one. Complex views may have
      multi presenters.

    MVC Pattern

    • Controller are based on behaviors and can be shared across
      views
    • Can be responsible for determining which view to display

    这是我在网上找到的最好的解释。


    以下是表示通信流的插图

    enter image description here

    enter image description here


    MVP不一定是视图负责的场景(例如,请参见Taligent的MVP)。我发现很不幸的是,人们仍然鼓吹这是一种模式(主管视图),而不是反模式,因为它与"它只是一种视图"(实用程序员)相矛盾。它只是一个视图"声明向用户显示的最终视图是应用程序的次要关注点。微软的MVP模式使得视图的重用变得更加困难和方便,从而使微软的设计师不必鼓励错误的做法。

    坦率地说,我认为对于任何MVP实现来说,MVC的底层关注点都是正确的,并且这些差异几乎完全是语义上的。只要在视图(显示数据)、控制器(初始化和控制用户交互)和模型(基础数据和/或服务)之间分离关注点,就可以实现MVC的好处。如果您正在实现这些好处,那么谁真正关心您的模式是MVC、MVP还是监控控制器呢?唯一真正的模式仍然是MVC,其余只是它的不同味道。

    考虑一下这篇激动人心的文章,它全面列出了许多不同的实现。你可能会注意到,他们基本上都在做同样的事情,但略有不同。

    我个人认为,MVP最近才被重新引入,作为一个吸引人的术语,来减少语义偏执者之间的争论,他们争论什么是真正的MVC,或者证明Microsoft快速应用程序开发工具的合理性。在我的书中,这些理由都不能证明它作为一种独立的设计模式存在。


    MVP:视图是负责的。

    在大多数情况下,视图会创建其演示者。演示者将与模型交互,并通过接口操作视图。视图有时会与演示者交互,通常通过一些接口。这归结到实现;您希望视图调用演示者的方法,还是希望视图具有演示者侦听的事件?归根结底就是:视图了解演示者。视图委托给演示者。

    MVC:控制器负责。

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


    enter image description here

    MVC(模型视图控制器)

    输入首先指向控制器,而不是视图。输入可能来自与页面交互的用户,但也可能来自于在浏览器中输入特定的URL。在这两种情况下,它都是一个控制器,与之接口以启动某些功能。控制器和视图之间存在多对一关系。这是因为单个控制器可以根据正在执行的操作选择要呈现的不同视图。注意从控制器到视图的单向箭头。这是因为视图对控制器没有任何知识或引用。控制器确实会传递模型,因此视图和传递到其中的预期模型之间存在知识,但不会传递给它服务的控制器。

    MVP(模型视图演示者)

    输入以视图开始,而不是演示者。视图和关联的演示者之间有一对一的映射。该视图保存对演示者的引用。演示者还对从视图触发的事件做出反应,因此它知道与之关联的视图。演示者根据其在模型上执行的请求操作更新视图,但该视图不了解模型。

    更多参考资料


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

    用户:单击单击…

    视图:那是谁?[ MVP·MVC]

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

    视图:好的,稍等……[ MVP·MVC]

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

    视图:嘿,演示者控制器,一个用户刚刚点击了搜索按钮,我该怎么做?[ MVP·MVC]

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

    视图:是的,…在这里……"钢琴"[MVP MVC]

    演示者:谢谢视图,…同时我正在查找模型上的搜索词,请给他/她显示一个进度条[MVP MVC]

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

    演示者控制器:嘿,模型,你有这个搜索词的匹配项吗?:"钢琴"[MVP MVC]

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

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

    (过了一会儿…)

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

    模型:我为您找到了一个列表,演示者,这里是json"["name":"钢琴老师","年份":2001","name":"钢琴","年份":1993"[MVP]

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

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

    主持人:感谢您的等待,我为您找到了一份匹配结果的列表,并以可展示的格式对其进行了安排:【2001年钢琴老师】、【1993年钢琴】。请在垂直列表中显示给用户。另外,请立即隐藏进度条[MVP]

    控制器:感谢等待视图,我已经询问了模型关于您的搜索查询。它说它找到了一个匹配结果的列表,并将它们存储在实例中名为"searchresultslist"的变量中。你可以从那里得到它。另外,请立即隐藏进度条[MVC]

    视图:非常感谢演示者[MVP]

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

    如果您感兴趣的话,我已经写了一系列关于应用程序体系结构模式(MVC、MVP、MVVP、Clean Architecture,…)的文章,并附带了一个Github报告。尽管该示例是为Android编写的,但其基本原则可以应用于任何媒体。


    • MVP=模型视图演示者
    • MVC=模型视图控制器

    • 两种表示模式。它们分离了模型(思考域对象)、屏幕/网页(视图)和用户界面的行为(演示者/控制器)之间的依赖关系。
    • 它们在概念上相当相似,人们根据口味对演示者/控制器进行不同的初始化。
    • 这里有一篇关于差异的伟大文章。最值得注意的是,MVC模式具有更新视图的模型。


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

    当使用被动视图时,您的视图通常实现一个细粒度的接口,属性或多或少直接映射到底层的UI小部件。例如,您可能有一个具有名称和地址等属性的ICustomerView。

    您的实现可能如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    public class CustomerView : ICustomerView
    {
        public string Name
        {
            get { return txtName.Text; }
            set { txtName.Text = value; }
        }
    }

    演示者类将与模型对话,并将其"映射"到视图。这种方法被称为"被动视图"。其好处是视图易于测试,并且在UI平台(Web、Windows/XAML等)之间更容易移动。缺点是您不能利用数据绑定之类的东西(它在WPF和Silverlight等框架中非常强大)。

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

    MVP的第三个"特色"(或者有人可能称之为单独的模式)是表示模型(或者有时称为模型视图视图模型)。与MVP相比,M和P"合并"成一个类。你有你的用户对象,你的用户界面小部件是数据绑定到,但你也有额外的用户界面特殊字段,如"isButtonEnabled"或"isReadOnly"等。

    我认为我找到的UI架构的最佳资源是Jeremy Miller在Build Your Own Cab Series目录中撰写的一系列博客文章。他涵盖了MVP的所有风格,并展示了实现它们的C代码。

    我还写了一篇关于Silverlight上下文中的模型视图viewModel模式的博客,在YouCard Re-Visited:实现viewModel模式。


    模型视图控制器

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

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

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

    enter image description here

    表示器

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

    If you want to see a sample with simple implementation please check
    this github post

    查询和显示数据库中用户列表的具体工作流可以这样工作:enter image description here

    What is the difference between MVC and MVP patterns?

    MVC模式

    • 控制器基于行为,可以跨视图共享

    • 可以负责确定要显示的视图(前控制器模式)

    MVP模式

    • 视图与模型的耦合更松散。演示者负责将模型绑定到视图。

    • 更容易进行单元测试,因为与视图的交互是通过接口进行的。

    • 通常视图到演示者将一个映射到一个。复杂视图可能有多个演示者。


    这两个框架都旨在分离关注点——例如,与数据源(模型)的交互、应用程序逻辑(或将此数据转换为有用的信息)(控制器/演示者)和显示代码(视图)。在某些情况下,该模型还可以用于将数据源转换为更高级别的抽象。MVC店面项目就是一个很好的例子。

    这里有一个关于MVC和MVP之间差异的讨论。

    区别在于,在MVC应用程序中,传统上视图和控制器与模型交互,而不是彼此交互。

    MVP设计让演示者访问模型并与视图交互。

    尽管如此,根据这些定义,ASP.NET MVC是一个MVP框架,因为控制器访问模型来填充视图,这意味着没有逻辑(只显示控制器提供的变量)。

    要了解ASP.NET MVC与MVP的区别,请查看Scott Hanselman的这个混合演示。


    它们各自解决不同的问题,甚至可以组合在一起,产生如下的效果

    The Combined Pattern

    这里还有MVC、MVP和MVVM的完整比较


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

    在体系结构上,MVP是基于页面控制器的方法,而MVC是基于前端控制器的方法。这意味着,在MVP标准的Web表单页面中,通过从代码背后提取业务逻辑,生命周期得到了增强。换句话说,page是为HTTP请求提供服务的。换言之,MVP IMHO是Web形式的进化增强类型。另一方面,MVC完全改变了游戏,因为请求在页面加载之前被控制器类截获,在那里执行业务逻辑,然后在控制器处理刚刚转储到页面的数据的最终结果("视图")。从这个意义上讲,MVC(至少对我来说)看起来非常适合监控路由引擎增强的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


    我同时使用了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中,控制器从模型中提取数据,并通过在视图中推送进行设置。

    在MVP中,您可以使用一个视图来处理多种类型的演示者,也可以使用一个演示者来处理不同的多个视图。

    MVP通常使用某种绑定框架,例如微软WPF绑定框架或HTML5和Java的各种绑定框架。

    在这些框架中,ui/html5/xaml知道presenter的每个ui元素显示的属性,因此当您将视图绑定到presenter时,该视图将查找属性,并知道如何从属性中提取数据,以及当用户在ui中更改值时如何设置这些属性。

    因此,例如,如果模型是一辆车,那么演示者就是某种类型的汽车演示者,将汽车属性(年份、制造商、座椅等)暴露在视图中。视图知道名为"Car Maker"的文本字段需要显示Presenter Maker属性。

    然后,您可以绑定到视图许多不同类型的演示者,所有这些演示者都必须具有maker属性-它可以是飞机、火车或其他任何视图都不关心的对象。只要视图实现了一个约定的接口,它就从演示者那里提取数据(不管是哪个)。

    这个绑定框架,如果你把它去掉,它实际上就是控制器。

    所以,你可以把MVP看作是MVC的进化。

    MVC很好,但问题是它的控制器通常是每个视图。控制器A知道如何设置视图A的字段。如果现在,您希望视图A显示模型B的数据,您需要控制器A知道模型B,或者您需要控制器A接收一个具有接口的对象-就像MVP一样,只需要没有绑定,或者您需要重写控制器B中的UI集代码。

    结论-MVP和MVC都是对UI模式的解耦,但MVP通常使用一个绑定框架,即下面的MVC。因此,MVP比MVC处于更高的体系结构级别,并且是MVC之上的包装模式。


    我简陋的短视:MVP适用于大尺度,MVC适用于小尺度。有了MVC,我有时会觉得V和C可能是一个单独的不可分割的组件的两面,直接绑定在M上,当向下走的时候,一个不可避免的会掉到这个上面?以缩短比例,如用户界面控件和基本小部件。在这个粒度级别上,MVP毫无意义。相反,当一个进入更大的范围时,适当的接口就变得更重要了,同样的,明确的职责分配也是如此,MVP出现了。

    另一方面,当平台特性倾向于组件之间的某种关系时,这种经验尺度规则的权重可能非常小,比如与Web的关系,在Web中,实现MVC似乎比MVP更容易。


    这是鲍勃叔叔的精彩视频,他在结尾简要介绍了MVC&MVP。

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

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

    希望这样会更好。


    MVC有很多版本,这个答案是关于smalltalk中的原始MVC的。简言之,它是image of mvc vs mvp

    本次演讲中,Droidcon NYC 2017-架构组件的清洁应用程序设计澄清了这一点。

    enter image description hereenter image description here


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


    最有价值球员

    MVP代表模型-视图-演示者。2007年初,微软推出了智能客户端Windows应用程序。

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

    视图事件绑定将从视图接口在演示者中实现。

    View是用户输入的发起程序,然后将事件委托给Presenter,Presenter处理事件绑定并从模型中获取数据。

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

    欺骗:在实现事件绑定时有点复杂,工作也更多

    MVC

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

    控制器是发起程序,它决定要呈现哪个视图。

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

    欺骗:有时,如果试图在同一个控制器中呈现多个视图,控制器的工作负载会太大。