什么进入“MVC”中的“控制器”?

我想我理解MVC的基本概念 – 模型包含应用程序的数据和行为,View负责将其显示给用户,Controller负责处理用户input。 我不确定的是控制器中究竟发生了什么

比方说,我有一个相当简单的应用程序(我特别想到Java,但我想其他地方也适用相同的原则)。 我把我的代码组织成3个名为app.modelapp.viewapp.controller

app.model包中,我有几个类反映了应用程序的实际行为。 这些extends Observable并使用setChanged()notifyObservers()在合适的时候触发视图进行更新。

app.view包有一个使用javax.swing组件来处理显示的类(或不同types的显示的几个类)。 其中一些组件需要反馈到模型中。 如果我理解正确的话,这个观点应该和反馈没有任何关系 – 这应该由主计长处理。

那么我真的把什么放在控制器? 我是否只需要调用Controller中的方法将public void actionPerformed(ActionEvent e)放入View中? 如果是这样,是否应该在控制器中进行任何validation? 如果是这样的话,我如何将错误信息反馈给视图 – 是否应该再次通过模型,还是应该直接将视图发送回视图?

如果validation是在视图中完成的,那么我在控制器中放置了什么?

对不起,我只是想logging我对这个过程的理解,希望有人能为我澄清这个问题!

在你提示的例子中,你是对的:“用户点击了”删除这个项目“button”,基本上只需要调用控制器的“删除”function即可。 然而,控制者不知道视图是什么样的,所以你的视图必须收集一些信息,例如“哪个项目被点击了?”。

在谈话forms中:

查看 :“嘿,控制器,用户刚刚告诉我他希望删除项目4。
控制者 :“嗯,检查他的凭据,他可以这样做…嘿,模型,我希望你得到项目4,做你所做的任何事情,删除它。
模型 :“项目4 …得到它,它被删除了,回到你,控制器。
控制器 :“在这里,我将收集新的数据集,回到你的视图。
观看 :“很酷,我现在将向用户展示新套装。”

在这一节的最后,你有一个select:要么视图可以做一个单独的请求,“给我最近的数据集”,从而更纯粹,或者控制器隐式地返回新的数据集与“删除“操作。

MVC的问题是人们认为视图,控制器和模型必须尽可能相互独立。 他们不是 – 一个观点和控制者往往交织在一起 – 把它想成M(VC)

控制器是用户界面的input机制,通常在视图中纠缠不清,尤其是GUI。 不过,视图输出和控制器input。 视图通常可以在没有相应的控制器的情况下工作,但是如果没有视图,控制器通常是非常有用的。 用户友好的控制器使用视图以更有意义,直观的方式解释用户的input。 这就是它很难将控制器概念从视图中分离出来。

以密封盒内的检测区域上的无线电控制机器人为例进行说明。

模型是关于状态和状态转换的,没有输出(显示)概念,或者触发状态转换的概念。 我可以得到机器人在场上的位置,机器人知道如何转换位置(向前/向后/向左/向右迈进一步,没有视图或控制器,很容易想象,但没有任何用处

考虑一个没有控制器的视图,例如另一个房间的networking中另一个房间里的某个人正在观看机器人位置,(x,y)坐标沿着滚动控制台向下stream动。 这个视图只是显示模型的状态,但是这个人没有控制器。 再一次,没有控制器,很容易想象这个观点。

想象一个没有视野的控制器,例如有人把无线电控制器调到机器人的频率,锁在衣柜里。 这个控制器发送input并导致状态转换,而不知道他们正在对模型做什么(如果有的话)。 容易想象,但没有从这个angular度来看,没有什么反馈真正有用。

大多数用户友好的用户界面与控制器协调视图,以提供更直观的用户界面。 例如,想象一个带有触摸屏的视图/控制器,以二维方式显示机器人的当前位置,并允许用户触摸正好位于机器人前方的屏幕上的点。 控制器需要关于视图的细节,例如视口的位置和比例,以及相对于屏幕上机器人的像素位置触摸的点的像素位置)来正确解释这个(不像锁在衣橱里的那个人无线电控制器)。

我有回答你的问题吗? 🙂

控制器是从用户input的任何用于使模型转换状态的东西。 尽量保持视图和控制器是分开的,但意识到它们往往是相互依赖的,所以它们之间的边界是模糊的,也就是说,将视图和控制器作为单独的包装可能不像你所期望的那样干净地分离像,但没关系。 视图来自模型,您可能不得不接受控制器与视图的干净分离。

在控制器中是否应该进行任何validation? 如果是这样的话,我如何将错误信息反馈给视图 – 是否应该再次通过模型,还是应该直接将视图发送回视图?

如果validation是在视图中完成的,那么我在控制器中放置了什么?

我说一个链接的视图和控制器应该自由交互,而不需要通过模型。 控制器接受用户的input并且应该进行validation(可能使用来自模型和/或视图的信息),但是如果validation失败,控制器应该能够直接更新其相关视图(例如错误消息)。

对此的酸性testing是问自己是否独立的观点(即通过networking观看机器人位置的人)是否应该看到别人的validation错误(例如,衣柜里的人试图告诉机器人走下场)。 一般来说,答案是否定的 – validation错误阻止了状态转换。 如果没有任何状态转移(机器人没有移动),则不需要告诉别的意见。 衣柜里的家伙没有得到任何反馈,他试图导致非法转换(没有视图 – 坏的用户界面),没有其他人需要知道这一点。

如果那个带触摸屏的家伙试图把机器人从场上送出去,他得到了一个很好的用户友好的信息,要求他不要把机器人送出检测区域,但是再也没有人需要知道这一点。

如果其他观点确实需要了解这些错误,那么您实际上是在说,来自用户的input和由此产生的任何错误都是模型的一部分,整个事情会稍微复杂一些。

这里有一篇关于MVC基础的好文章 。

它指出 …

控制器 – 控制器将与视图的交互转换为由模型执行的操作。

换句话说,你的商业逻辑。 控制器响应用户在视图中采取的行动并作出响应。 你把validation放在这里,如果validation失败或成功(错误页面,消息框,无论),select适当的视图。

福勒还有一篇很好的文章 。

MVC模式只是希望你把表示 (=视图) 与buisiness逻辑 (=模型) 分开 。 控制器部分只会造成混淆。

根据你的问题,我觉得你对模型的作用有点模糊。 该模型固定在与应用程序相关的数据上; 如果应用程序有一个数据库,模型的工作将是谈话。 它也将处理与该数据相关的任何简单的逻辑; 如果你有一个规则,说所有的情况下TABLE.foo ==“万岁! 和TABLE.bar ==“Huzzah!” 然后设置TABLE.field =“W00t!”,然后你想模型照顾它。

控制器是应该处理大部分应用程序的行为。 所以要回答你的问题:

“我是否只需要调用Controller中的一个方法,将public void actionPerformed(ActionEvent e)放在View中?”

我会说不。 我会说,应该住在控制器; View应该简单地将来自用户界面的数据提供给Controller,让Controller决定应该调用哪些方法。

“如果是这样,是否应该在控制器中进行任何validation?”

大部分的validation应该由控制器来完成。 它应该回答数据是否有效的问题,如果不是,则向视图提供相应的错误消息。 实际上,为了改善用户体验,您可以将一些简单的完整性检查结合到View层中。 (我主要想的是Web环境,在用户点击“Submit”时可能会popup一个错误消息,而不是等待整个提交 – >处理 – >加载页面循环,然后告诉他们他们搞砸了)小心一点, 你不想重复努力,而且在许多环境中(同样,我在考虑networking),你经常不得不将任何来自用户界面的数据视为一团糟的肮脏谎言,直到你确认它确实是合法的。

“如果是这样,我如何将错误消息反馈给View – 是否应该再次通过Model,还是Controller应该直接发回View?”

你应该设置一些协议,在Controller不知道下一步会发生什么,直到Controller告诉它。 在用户重击那个button后,你给他们看什么屏幕? 视图可能不知道,控制器可能不知道,直到它看到刚刚得到的数据。 可能是“按预期转到其他屏幕”或“保持在此屏幕上,并显示此错误消息”。

根据我的经验,模型和视图之间的直接交stream应该是非常非常有限的,视图不应该直接改变任何模型的数据。 那应该是pipe理员的工作。

“如果validation是在视图中完成的,那么我在控制器中放什么?

往上看; 真正的validation应该在控制器中。 希望你对现在应该放在控制器中有一些想法。 🙂

值得注意的是,它可以在边缘都变得模糊起来; 就像大多数软件工程一样复杂的事情,判断电话会比比皆是。 只要使用你最好的判断,尽量保持在这个应用程序的一致性,并尝试将你学到的课程应用到下一个项目。

实际上,我从未发现控制器概念是一个特别有用的概念。 我在代码中使用严格的模型/视图分离,但没有明确定义的控制器。 这似乎是一个不必要的抽象。

就个人而言,全面的MVC看起来像工厂devise模式,因为它很容易导致混淆和过度复杂的devise。 不要成为一名build筑宇航员 。

控制器真的是视图的一部分。 它的工作是确定需要哪些服务来完成请求,将视图中的值解组成为服务接口需要的对象,确定下一个视图,然后将响应封送到下一个视图可以使用的forms。 它还处理所有抛出的exception,并将它们呈现到用户可以理解的视图中。

服务层是知道用例,工作单元和模型对象的东西。 对于每种types的视图,控制器都会有所不同 – 对于桌面,基于浏览器,Flex或移动UI,您将不具有相同的控制器。 所以我说这是用户界面的一部分。

面向服务:这就是工作完成的地方。

控制器主要用于视图和模型之间的协调。

不幸的是,它有时最终与视图混合在一起 – 在小应用程序中,虽然这不是太糟糕。

我build议你把:

 public void actionPerformed(ActionEvent e) 

在控制器中。 那么你的视图中的动作监听器应该委托给控制器。

至于validation部分,你可以把它放在视图或控制器中,我个人认为它属于控制器。

我肯定会推荐看一看被动视图和监督演示者(这基本上是模型视图演示者分成的 – 至less是福勒)。 看到:

http://www.martinfowler.com/eaaDev/PassiveScreen.html

http://www.martinfowler.com/eaaDev/SupervisingPresenter.html

下面是我使用的经验法则:如果它是一个专门用于页面上的操作的过程,则它属于控制器,而不是模型。 该模型应该只对数据存储提供一个连贯的抽象。

我在开发人员编写的大型web应用程序后,想到了解MVC,但实际上并没有这样做。 他们的“控制器”被简化为八行调用的静态类方法,这些方法通常被称为“无处不在”: – 使得他们的模型不仅仅是创build名称空间的方式。 重构这个正确的做三件事:所有的SQL转移到数据访问层(又名模型),使控制器代码有点更加冗长,但更容易理解,并减less旧的“模型”文件为空。 🙂

据我了解,控制器从用户界面操作转换到应用程序级操作。 例如,在一个video游戏中,控制器可能会翻译“移动鼠标这么多像素”为“想在这样一个方向看,在一个CRUD应用程序,翻译可能是”点击这样一个button“ “打印这个东西”,但概念是一样的。

还要注意每个Swing小部件都可以被认为包含三个MVC组件:每个都有一个Model(即ButtonModel),一个View(BasicButtonUI)和一个Control(JButton本身)。

你基本上是正确的,你把什么放在控制器。 这是模型与视图交互的唯一方式。 actionperformed可以放在View中,但是实际的function可以放在另一个可以作为Controller的类中。 如果你打算这样做的话,我build议查看命令模式,这是一种抽象所有具有相同接收器的命令的方法。 对不起,这个题外话。

无论如何,一个适当的MVC实现将只有以下交互:模型 – >视图视图 – >控制器控制器 – >视图

唯一可能存在另一种交互的地方是,如果您使用观察者来更新视图,则视图将需要向控制器询问所需的信息。

我们这样做,使用控制器主要是为了处理和响应用户驱动的input/操作(除了视图,数据和显而易见的_Model之外的其他东西)

(1)(响应,反应 – Web应用程序响应用户做了什么)Blog_Controller

– >主()

– > handleSubmit_AddNewCustomer()

– > verifyUser_HasProperAuth()

(2)(“业务”逻辑,Web应用程序“认为”什么以及如何)Blog_Logic

– > sanityCheck_AddNewCustomer()

– > handleUsernameChange()

– > sendEmail_NotifyRequestedUpdate()

(3)(视图,门户网站如何“出现”)Blog_View

– > genWelcome()

– > genForm_AddNewBlogEntry()

– > genPage_DataEntryForm()

(4)(仅在每个Blog *类的_ construct()中获取的数据对象,用于将所有webapp / inmemory数据作为一个对象保存在一起)Blog_Meta

(5)(基本数据层,读/写DB)Blog_Model

– > saveDataToMemcache()

– > saveDataToMongo()

– > saveDataToSql()

– > loadData()

有时候,我们会在C或者L中的某个方法的位置上感到困惑,但是这个模型是坚如磐石,清晰的,而且由于所有内存中的数据都驻留在_Meta中,所以这也是一个不容忽视的方法。 。 我们最大的飞跃就是采用_Meta的使用,顺便说一句,这清除了各种_C,_L和_Model物体的所有碎屑,使它们在精神上容易pipe理,再加上一举,它给了我们什么称为“dependency injection”,或者是一种将整个环境与所有数据一起传递(其优点是易于创build“testing”环境)的方式。