65.9K
CodeProject 正在变化。 阅读更多。
Home

MVC 和 MVP 的区别( 针对初学者)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (39投票s)

2011年11月23日

CPOL

7分钟阅读

viewsIcon

276267

downloadIcon

3036

本文旨在用简单的术语描述 MVC 和 MVP

引言

在现代世界中,能够设计高效解耦系统的架构师被认为是公司宝贵的财富。这是因为解耦系统可以降低维护成本,并帮助开发人员在不影响整体系统的情况下快速修改程序。解耦系统促进并行开发,这意味着工作可以分配给不同的开发人员,从而大大缩短开发时间。在本文中,我将介绍用于开发解耦系统的两种最流行的模式。它们被称为模型-视图-控制器 (MVC) 和模型-视图-展示器 (MVP)。

我的解释基于桌面应用程序开发。

(M)odel (V)iew (C)ontroller

MVC 架构是实现关注点分离的最古老模式之一。MVC 由三个层组成:模型 (Model)、视图 (View) 和控制器 (Controller)。

经典的 MVC 存在于这样一个时代:屏幕上的每一个控件/组件都被认为是“哑巴”的,每个控件都有自己的控制器来管理其上的用户交互。因此,如果存在 10 个组件,则需要存在 10 个控制器。在这种情况下,每个组件都被视为一个视图。Windows GUI 系统的出现改变了这一局面。控件-控制器关系变得过时。控件获得了响应用户操作的智能。在 Windows 世界中,视图是所有控件/组件存在的表面,因此只需要一个控制器。视图可以接收事件并寻求控制器的帮助来进行进一步处理。

模型 (Model) – 模型接收控制器的输入,并确定需要什么数据来满足控制器提出的请求。模型还可以根据需要与数据库或其他持久存储进行事务处理。一旦收集到所需信息,它就会通过引发适当的事件,(经由控制器)将新数据通知视图。

视图 (View) – 视图承载了最终用户与应用程序交互所需的所有 UI 控件。它的工作是监控最终用户的手势,并将它们传递给控制器进行进一步处理。视图处理从模型接收到的事件通知,并可能请求任何新数据以便在屏幕上进行渲染。然而,在某些变体中,控制器可以被指定从模型检索数据集,对其进行格式化,然后将其发送到视图。在这里,视图的工作是渲染从视图接收到的数据,而不进行任何其他处理。

控制器 (Controller) – 控制器可以被视为视图的扩展或个人助理,所有源自视图的事件都由控制器处理。控制器还会代表视图告知模型,视图上发生了一些事件,可能需要一些新数据。

public Controller(IViewBase view)
    {
        _view = view;
        _model.ModelChanged += new EventHandler(_model_ModelChanged);    
    }

通常,控制器的构造函数会接受视图作为参数。控制器将利用此参数访问视图的方法。正如您所见,控制器正在订阅 ModelChanged 事件。当模型的状态发生变化时,就会引发此事件。控制器捕获此事件以通知视图模型状态已更改。

(M)odel (V)iew (P)resenter

MVP 系统是 MVC 的演进版本。在此模式中,视图接收 UI 事件并根据需要调用展示器 (Presenter)。展示器还负责使用模型生成的新数据更新视图。

模型 (Model) - 模型可以被视为数据的接口。程序中任何需要数据来工作的部分都必须通过维护模型部分的开发人员定义的接口或函数。通常,模型包含所有用户提交数据的验证例程。

视图 (View) – 视图顾名思义,是最终用户交互的部分。这部分开发可以委托给专门的设计师。一个程序可以有任意数量的视图。

展示器 (Presenter) – 展示器充当中介,实现解耦。响应用户事件所需的所有业务逻辑都写在展示器层内。通常,视图只有事件处理程序和调用适当展示器函数的逻辑,这有助于视图工作的人员专注于设计用户界面,而不必担心代码隐藏文件。展示器还负责从模型检索请求的数据并对其进行格式化,以便视图可以零开销地渲染它。

MVP 是 MVC 的后继者,也是 .NET 世界中用于构建解耦系统的流行设计模式之一。采用 MVP 模式设计的系统也促进了单元测试,使您的程序更加稳健。

定义通信接口

为了使 MVP 生效,必须为模型和视图定义一个接口或契约,以便展示器知道何时调用哪个函数。

interface  IStudentModel
    {
        void Save(string username,string email );
        string Get(string username);
        bool ValidateEmail(string email);
        bool IsEntryExisting(string username);
    }

interface IStudentView
    {
        String UserName { get; set; }
        String Email { get; set; } 

    }

通常,展示器类的构造函数会接受视图和模型作为参数。一旦这些信息传递给展示器,它就负责视图和模型之间的任何通信。展示器的依赖注入功能有助于使用模拟对象进行单元测试。

MVP 被动视图 (Passive view) vs MVP 监督控制器 (Supervising Controller)

MVP (监督控制器) 是 MVP 模式的另一种变体。与上面解释的 MVP (被动视图) 不同,MVP (SC) 中的视图更智能。视图可以直接与模型通信并根据需要查询数据。展示器的作用是通知模型视图中发生了某些活动,这可能会导致状态更改。展示器还将模型的一个引用传递给视图,以便视图可以在模型状态更改时直接与之交互。简而言之,MVP (SC) 在大多数方面都类似于 MVC。

区别表

职责表

MVC

MVP

MVC/MVP 常见问题解答

问) 我认为所有 UI 修改(例如,当达到阈值时更改文本前景色)都需要在视图级别完成,因为模型没有与控制器直接联系。这是正确的吗?

答) 是的。如果视图直接从模型检索新数据。

否。如果视图正在寻求控制器的帮助来查询新数据。在这种情况下,控制器可以格式化数据并将其发送到视图。

问) 我看到模型和视图之间有一条虚线连接,表示“间接”关系。您能解释一下这种间接关系意味着什么吗?

模型不知道视图,但视图知道模型。

问) 我在一些 MVP 解释中看到过诸如 interactor、command、selection 之类的对象。我什么时候应该使用它们?

答) 这些对象存在于 Mike Potel 的 MVP 中,当时的用户控件和 GUI 还没有像今天这样开发。在当前的 Windows 世界中,我们可以非常有效地在没有问题中提到对象的情况下执行 MVP 模式。

请记住,设计模式是指导您解决常见问题的宽松指南。不一定非要严格遵循设计模式的核心。您可以根据自己的需求调整设计模式。

问) 有展示器有什么好处?- 为什么视图不能立即与模型通信?

答) MVP 模式背后的基本思想是关注点分离。这提高了可测试性,并且可以引入模拟对象来测试域部分。此外,我们可以更改视图,它们可以以不同方式表示模型数据。

问) 在 MVC/MVP 架构中,我应该在哪里编写验证?

答) 基本的控件验证,如空字段验证,应在视图级别完成。任何与数据库相关的内容都应写在模型内部,作为 public 方法。控制器将使用此方法在数据到达模型之前进行验证。

历史

  • 2011 年 11 月 23 日:初始版本
© . All rights reserved.