mvc 在哪里保存对控制器的引用?

Ren*_*rde 3 java model-view-controller design-patterns javafx

在我的程序中,控制器只是用一个函数挂钩按键。那么应该 ikeep 引用它吗?例如保持参考

Model model = new Model();
View  view  = new View(model);
Controller controller = new Controller(model,view);
Run Code Online (Sandbox Code Playgroud)

或没有

Model model = new Model();
View  view  = new View(model);
new Controller(model,view);
Run Code Online (Sandbox Code Playgroud)

内部控制器

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");
}
Run Code Online (Sandbox Code Playgroud)

也许我错误地实现了 Controller 类并且误解了 mvc 模式。但是到目前为止我写的内容没有理由让我保留对控制器对象的引用。

Jam*_*s_D 7

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

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

对我来说,桌面 GUI 上下文中MVC 的权威指南是 Martin Fowler关于 GUI 体系​​结构文章

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

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

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

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

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

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

JavaFX 实际上为这种架构风格提供了“开箱即用”的支持,使用 FXML 作为(通常是被动的)视图,并提供了方便的方法来连接到它调用的控制器(这可能更像是一个演示者) . JavaFX 属性使编写模型很容易,这些模型可以根据需要由视图或演示者轻松观察。

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

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