模型 - 视图 - 控制器(MVC)优于模型视图的优势是什么?

时间:2012-01-14 17:33:53

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

任何人都可以举例说明为什么使用MVC而不是简单的模型和仅查看是有利的。

注意:无论是MVC还是MVP(Model-View-Presenter),我都在谈论View接收输入的那个,然后Controller会通过将输入解释为某个动作来响应输入事件由模型完成。当模型更改时,View将通过响应模型中的事件来更新自身。

简单地让模型响应视图中的事件,反之亦然,这有什么不利之处?

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

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

3 个答案:

答案 0 :(得分:4)

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

  

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

模型应该以这样一种方式公开简单的CRUD方法,即使用这些方法的人不必了解传递的更新对象,也不必了解模型中真正发生的事情。

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

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

让我走得更远。假设你有一个视图,一个tablegrid,以及一个在网格中选择了enabled属性依赖于item的控件 - 你可以创建一个在内部处理这些控件和这个逻辑的视图,这可能就是你要走的路。在这样一个简化的例子中。

但是你的观点越原子化,它们变得越可重用,所以你为每一个控制器创建了一个视图。现在,您正在查看视图必须彼此了解的情况,以便为自己注册正确的通知...

这是控制器介入的地方,因为我们希望将所有这些依赖关系粘贴到他身上,即长期一次性的依赖关系。因此,控制器管理这种类型的视图到视图通知方案。

现在你的观点是无知的,因为它们可以是独立的,因此可以重复使用。

您可以在不必了解系统的情况下编写视图代码,也可以根据需要调用“业务逻辑”。你可以编写模型而不必过多地了解你的目标(虽然它确实有助于调整模型以使其能够返回你想到的数据集)....但是控制器,它们是最后的,你必须拥有在你把所有东西连在一起之前,前两个已经确定了。

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

所以,最终这意味着视图不应该(在下面告诫)具有如下所示的函数/属性:

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必须是所有视图功能的接口,而是它们应该处理'edge case'属性以及你可以在传统硬盘中暴露的普通props / cmds - 链接方式。将其视为“扩展属性”处理程序。

这样,(再做一次),假设你正在构建一个框架,你的按钮不再具有buttonIcon属性。这很酷,因为你有先见之明来创建一个按钮视图界面,​​其中buttonIcon是一个扩展属性,并且在视图内你的条件代码在收到set / get时会执行no-op。

总之,我试图说MVC的编码目标应该是将Model和View通用接口赋予其底层组件,因此当您编写Controller时,您不必仔细考虑谁你控制着。虽然控制器(看似不公平)在长期可重复使用中被设置为牺牲品 - 但这并不意味着你的所有控制器都注定要死亡。

他们希望很小,因为很多他们的'思考'被推到了半智能模型和视图以及其他控制器(例如:控制器来排序网格或操纵TreeView) - 所以它们可以很小很容易看到并有资格在下一个项目中重复使用 - 或者克隆和调整以适合。

答案 1 :(得分:1)

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

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

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

它还可以使未来更改框架变得更容易 - 模型可能不会改变太多,因此更便携。

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

答案 2 :(得分:1)

MVC / P(我在这里谈论监督控制器)的优点还包括:

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

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

  • 您还可以让平面设计师制作您的观点,而不是看到您的代码,并且在修复您的观看时不会弄乱您的代码。