【问题标题】:What is the advantage of Model-View-Controller (MVC) over Model-View?Model-View-Controller (MVC) 与 Model-View 相比有什么优势?
【发布时间】:2012-02-10 10:45:47
【问题描述】:

谁能举例说明为什么使用 MVC 而不是更简单的模型和视图更有利。

注意:不管是MVC还是MVP(Model-View-Presenter),我说的是View接收输入,然后Controller会响应输入事件,将输入解释为一些动作由模型完成。当模型发生变化时,视图将通过响应来自模型的事件来更新自身。

简单地让模型响应视图中的事件有什么缺点,反之亦然?

在 MVC 中,如果我以影响控制器的方式更改模型,那么我将不得不在控制器中进行更改。在模型视图中,如果我更改模型,我将不得不更新视图。

所以,我们似乎通过添加“控制器”部分来引入复杂性?

【问题讨论】:

    标签: model-view-controller view model controller mv


    【解决方案1】:

    在 MVC 中,模型对其环境视而不见,视图也可以——将其事件(盲目地)传递给控制器​​,控制器更了解视图和模型。因此,总而言之,控制器是系统中“不可重复使用”的一次性部分,因为它是最能感知上下文的组件。

    如果我以影响控制器的方式更改模型...

    模型应该公开简单的 CRUD 方法,这样使用这些方法的人不必知道传递的更新对象的任何信息,也不必知道模型内部到底发生了什么。

    这意味着视图,IMO,必须通过创建传递的记录来做一些工作,因为控制器应该是无状态的并且视图更持久。控制器被触发并“启动”处理传递的对象并且没有状态。

    传递的数据是通过某种通用约定创建的。

    让我更进一步。假设您有一个视图、一个表格网格,并且在网格中选择了一个其启用属性依赖于项目的控件——您可以创建一个在内部处理这些控件和此逻辑的视图,这可能是要走的路在这样一个简化的例子中。

    但是您的视图越原子,它们就越可重用,因此您为每个,是的,每个控件创建一个视图。现在您正在研究一种情况,即视图必须相互了解才能注册自己以获取正确的通知...

    这是控制器介入的地方,因为我们想把所有这些依赖项都粘在他身上,长期一次性的。所以控制器管理这种类型的视图到视图通知方案。

    现在您的视图是无知的,因为它们可以是独立的,因此可以重用。

    您可以编写视图,而无需了解系统或他们喜欢的“业务逻辑”。您可以编写模型而不必对您的目标有太多了解(尽管它确实有助于调整模型以使其能够返回您想到的数据集)....但是控制器,它们是最后的,您必须拥有在你把东西连接在一起之前,前两个已经确定了。

    这是另一件需要考虑的事情——就像模型应该抽象出来并为其管理的数据的底层实现提供通用接口一样(客户端不知道数据是否来自数据库、文件、程序设置等)——视图还应该抽象出它正在使用的控件。

    因此,最终这意味着视图不应该(以下警告)具有如下所示的功能/属性:

    public property BackgroundColor{get;set}
    

    也没有

    public function ScrollBy(x,y){}
    

    但是:

    public SetProp(string name, object val){}
    

    public DoCmd(string name, object val){}
    

    这有点做作,记得我最后说过......你问为什么这是个好主意?

    考虑到可重用性,考虑到有一天您可能希望将某些东西从 WinForms 移植到 Flex,或者只是想使用可能不会提供相同功能的新型控件库。

    我在这里说“移植”,但这并不是我们的目标,我们并不关心移植这个特定的应用程序,而是让底层 MVC 元素足够通用,以适应新的风格——在内部,留下一个一致且与能力无关的外部接口完好无损。

    如果您不这样做,那么当您的新风格出现时,您对(可能可重用/可重构/可扩展的)控制器中的视图属性的所有硬引用都必须被删除。

    这并不是说这些通用的 setter 和 cmds 必须是所有视图功能的接口,而是它们应该处理“边缘情况”属性以及您可以在传统硬中公开的普通 props/cmds -链接方式。将其视为“扩展属性”处理程序。

    这样,(再次设计),假设您正在构建一个按钮不再具有 buttonIcon 属性的框架。这很酷,因为您有远见地创建了一个按钮视图界面,​​其中 buttonIcon 是一个扩展属性,并且在视图内部,您的条件代码现在在接收到 set/get 时执行无操作。

    总之,我想说 MVC 的编码目标应该是为它们的底层组件提供 Model 和 View 通用接口,因此当您编写 Controller 时,您不必费力地考虑谁你在控制。虽然控制器被设置为(似乎不公平地)从长远来看可重用性的牺牲品 - 这并不意味着您的所有控制器都注定要死亡。

    希望它们很小,因为它们的许多“思考”已被推到半智能模型和视图以及其他控制器中(例如:对网格进行排序或操作 TreeView 的控制器)——因此它们可以很小易于查看并有资格在您的下一个项目中重用 - 或克隆和调整以变得合适。

    【讨论】:

    • 我将举一个简单的例子说明为什么我没有看到优势。假设我们正在谈论汽车。点击 Car View 的 Accelerate 按钮,Controller 通过调用 Model.Accelerate() 进行响应,然后 Model 的速度发生变化,View 响应 Model 事件并更新屏幕上的速度读数。现在,在模型视图(MV)中,当单击按钮时,视图调用 Model.Accelerate(),并且在不涉及控制器的情况下也会发生同样的情况。在 MVC 中,如果我将 Accelerate() 更改为 increaseSpeed(),我将不得不更新控制器以调用这种方法。在 MV 的情况下,我会做同样的更新,但视图。
    • 继续之前的评论:因此,优势仅适用于以下情况: 1. 您的观点并非特定于您当前的项目(这种情况很少见)。 2. 想不出来!!! (可能缺乏经验)。
    • 你有一个一对一的例子。视图必须以影响模型的每一种方式了解模型的所有信息。那是一堆依赖项都集中在一个地方。而对于控制器,该块被拆分 - 每个事件都有一个单独的控制器 - 如果在事件发生时模型必须发生一些更奇特的事情,则更改发生在控制器中(即,控制器的重用潜力通过它增加仅适用于一个事件)。以您的方式,每次增强/添加都会降低视图的可重用性。
    • 你说视图对当前项目来说太具体了。这告诉我你做错了什么。可能会因为您使用的是 MVC 框架类型而出现混淆(他们在粒度上做出妥协以拥有更简单的系统)。我的 cmets 倾向于 PureMVC 之类的东西,或者你负责的自制解决方案。这意味着视图(PureMVC 中的中介)与一个控件或一组非常简单的无聊控件(如子菜单)有关。所以视图就像一个包装器......它是泛化的,但也是你为任何复杂控件放置实用程序的地方......继续。
    • 这是关于视图的另一件事——它们不必绑定到特定的控件,但可以管理全局关注点。例如,您可以有一个焦点调解器(一个视图,相同的东西)来跟踪焦点问题(禁用其他控件等)并且是焦点问题的首选。或者管理所有控件的全局外观方案的视图。我认为它们是功能层。
    【解决方案2】:

    它实际上通过将工作流逻辑与域逻辑分离来降低复杂性。它还使编写单元测试更容易,并使您的应用程序更易于维护和扩展。

    想象一下,如果您想添加一个新的数据类型。使用上述方法,您可能会在新类中复制大量工作流逻辑,因为它可能与域逻辑紧密耦合。

    将工作流逻辑分离到控制器中所涉及的规则使您更有可能减少工作流和域逻辑之间的依赖关系。添加新数据类型会更简单,您创建新域对象并查看可以重用多少控制器,例如通过从控制器超类继承。

    这也将使将来更改框架变得更容易 - 模型可能不会改变太多,因此更便携。

    话虽如此,您可能希望根据您用作表示层的内容来研究 MVVM:Benefits of MVVM over MVC

    【讨论】:

      【解决方案3】:

      MVC/P(我这里说的是监督控制器)相对于 MV 的优势包括:

      • 如果需要,您可以在控制器中处理复杂的数据绑定代码。

      • 您可以在没有 UI 测试框架的情况下测试复杂的表示逻辑。

      • 您还可以让图形设计师制作您的视图,但看不到您的代码,并且在他们修复您的视图时不会弄乱您的代码。

      【讨论】:

        猜你喜欢
        • 2014-01-10
        • 2015-05-14
        • 2012-11-01
        • 2023-03-24
        • 1970-01-01
        • 2011-12-04
        • 2019-05-09
        • 1970-01-01
        • 2012-06-19
        相关资源
        最近更新 更多