【问题标题】:mvc where to keep the reference to controllers?mvc 在哪里保存对控制器的引用?
【发布时间】:2016-05-28 02:03:33
【问题描述】:

在我的程序中,控制器只是将按键与功能挂钩。 那么应该引用它吗? 例如。 保留参考

Model model = new Model();
View  view  = new View(model);
Controller controller = new Controller(model,view);

没有

Model model = new Model();
View  view  = new View(model);
new Controller(model,view);

内部控制器

public Controller(Model model, View view)
{
    this.model = model;
    this.view = view;
    view.setOnKeyPressed(this::doSomething);
}

public void doSomething(KeyEvent event)
{
    System.out.println("key pressed");
}

也许我错误地实现了 Controller 类并误解了 mvc 模式。但就我目前所写的内容而言,我没有理由保留对控制器对象的引用。

【问题讨论】:

  • 如果您不需要明确引用控制器,那么就没有必要保留一个,恕我直言(其他意见可能会有所不同)。你可能会发现你以后需要一个。请注意,当您注册按键处理程序时,此处的视图隐含地提供了对控制器的引用。

标签: java design-patterns model-view-controller javafx


【解决方案1】:

当在 GUI 上按下一个键时,您需要为您创建一个控制器实例。所以你需要它是一个监听按键的监听器。

一旦注册了 GUI 侦听器,框架就有责任实例化该控制器并将视图传递给该控制器。

(因此,您永远不需要控制器的句柄 - 它的句柄始终在框架中。)

接下来,当您在带有视图的控制器中时,您可以根据视图中的值来确定要创建或获取的模型...

这就是所有 MVC 的工作方式...

【讨论】:

  • 也许与设计用于位于 HTTP 等通信协议之上的 MVC 架构有一些相似之处,但在桌​​面环境中看起来确实不像 MVC GUI 库,例如 JavaFX。例如,无需任何框架即可轻松实现 MVC。
【解决方案2】:

我不确定这个问题是否真的可以回答,因为它可能过于宽泛和/或过于基于意见。不过……

MVC 是一个定义非常松散的模式。它确实可以追溯到大约 40 年(或更长时间)到 Xerox PARC 研究 GUI 开发的早期阶段。由于它已经存在了很长时间并且它的主要用例(GUI 架构)已经有了显着的发展,它已经分支成许多子模式和变体。因此,您会发现“MVC”对不同的开发人员意味着许多不同的东西。特别是,Web 应用程序环境中的 MVC 与您所谈论的上下文中的 MVC 有些不同(imo),因为在 Web 应用程序环境中,它必须位于请求-响应周期的顶部。这个答案/讨论的其余部分集中在 MVC 的原始“厚客户端”版本,其中视图和控制器都在同一进程的内存中,并且可以直接通信(而不是通过 HTTP 等请求-响应协议)。

对我而言,桌面 GUI 上下文中的 MVC 权威指南是 Martin Fowler 的 essay on GUI architectures

我会说“经典”MVC 的特点是:

  • 具有三个组件:
    • 提供对数据的访问的模型可能会提供用于注册侦听器以通知数据更改的机制,并且不了解数据的呈现方式
    • 一个视图,观察模型中的数据并在数据发生变化时自我更新(这将经典 MVC 与某些形式的 MVP 区分开来)
    • 提供“视图逻辑”的控制器:通常这意味着它响应用户输入并更新模型(而不是视图)作为结果

所以模型应该对视图和控制器一无所知。视图对控制器一无所知,但需要对模型的引用,以便它可以显示数据,观察数据的变化,相应地更新表示。控制器还需要对模型的引用,因此它可以根据用户输入更新数据。通常,控制器还需要对视图的引用,因为它通常需要向视图中的小部件注册事件处理程序,以便了解它必须处理的用户输入。

这种设计背后的驱动力是允许保持同步的数据的多个表示(将表示视为视图和控制器的组合)。该模式通过引用模型中的所有内容来实现这一点:一个演示文稿的控制器可能会更新模型;由于所有视图都观察模型,因此它们都看到了这些更改,并且每个视图都负责相应地更新自己。更改视图的控制器不需要知道可能正在观察数据的任何其他视图,以使所有视图保持同步。

您的应用程序本身肯定需要访问模型;它可能需要访问数据,可能需要从外部(即非用户驱动)因素对其进行修改,在关机时保留数据等。您的应用程序可能需要访问视图(它需要在某处显示它,可能需要处理它在关机等)。您的应用程序可能需要也可能不需要访问控制器。在最纯粹的形式中,一旦控制器知道如何观察用户事件的视图,并且知道如何更新模型,您就再也不需要与它通信了。 (如果你想改变“外部”事件的状态,你可以通过模型而不是通过控制器来实现。)

已经出现了这个想法的几种变体(参见 Fowler)。 Model-View-Presenter 是一种流行的(也有自己的几种变体)。在这个变体中,控制器被替换为“Presenter”,它承担了更新视图的部分甚至全部责任。在这种形式的一种形式中(Fowler 称之为“被动视图”),视图完全没有逻辑,只是对控件进行布局。演示者处理用户输入,当用户输入发生在视图上时更新视图和模型,并观察模型,如果它发生变化则更新视图。这种变体在可测试性和调试能力方面具有优势,但可以说视图和呈现器之间的耦合比视图和控制器之间的耦合更紧密。 (为一个视图提供多个控制器相对容易;为被动视图提供多个演示者变得更加复杂,并且演示者通常必须相互了解。)

JavaFX 实际上为这种架构风格提供了“开箱即用”的支持,将 FXML 用作(通常是被动的)视图,并提供了方便的方法来挂钩它所谓的控制器(这可能更多主持人)。 JavaFX 属性使编写模型变得容易,这些模型可以根据需要由视图或演示者轻松观察。

实际上,在大多数情况下,您通常会发现这些作品的混合效果最好。中大型应用程序将在多个地方、多个不同规模上使用 MVC/MVP 类型的模式。您经常会发现控制器/演示者之间相互了解一些知识并在它们之间进行通信很方便,在这种情况下,您显然需要保留对控制器的引用。

所以你的问题的答案可能只是“这取决于你需要什么”。如果您不需要对控制器的引用,则无需保留一个。实际上,在 JavaFX 中 FXML 的标准使用中,控制器 class 只是在视图(FXML)中指定; FXMLLoader 根据该信息实例化控制器,并根据需要将视图和控制器连接在一起。您通常甚至根本没有在代码中引用控制器实例。不过,正如this popular JavaFX question 中所见,您当然可以在需要时获得一个。在一个完全“纯”的经典 MVC 中,所有状态更改都是通过模型进行的,并且视图会观察它,因此您永远不需要访问控制器。 Fowler 指出了一些很好的例子,这些例子并不像听起来那么干净:首先,某些状态和相关逻辑实际上是视图的一部分,在模型中没有位置,其次,注册/通知机制可以使调试应用程序变得非常困难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 2010-10-10
    • 2014-07-16
    • 1970-01-01
    • 2015-09-06
    相关资源
    最近更新 更多