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

时间:2016-02-16 17:00:14

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

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

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模式。但是到目前为止我写的内容没有理由让我保持对控制器对象的引用。

2 个答案:

答案 0 :(得分:3)

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

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

对我来说,桌面GUI环境中MVC 的权威指南是Martin Fowler的essay on GUI architectures

我会说"经典" MVC的特点是:

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

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

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

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

出现了这种想法的几种变体(见福勒)。一种流行的(它也有自己的几种变体)是Model-View-Presenter。在此变型中,控制器由" Presenter"它承担了更新视图的一些甚至全部责任。在这种形式中(福勒称之为#34;被动视图"),视图完全没有逻辑,只是放置了控件。演示者处理用户输入,在视图上发生用户输入时更新视图和模型,并观察模型,如果视图发生更改则更新视图。这种变体在可测试性和调试能力方面具有优势,但视图和演示者之间的耦合可能比视图和控制器之间的耦合更紧密。 (为视图提供多个控制器相对容易;为被动视图提供多个演示者变得更加复杂,演示者通常必须彼此了解一些。)

JavaFX实际上提供了开箱即用的#34;支持这种架构,使用FXML作为(通常是被动的)视图,并提供方便的方式来挂钩它所谓的控制器(可能更像是一个演示者)。 JavaFX属性使编写模型变得容易,视图或演示者可以根据需要轻松观察模型。

在实践中,您通常会在大多数情况下最好地找到这些作品的混合体。中型大型应用程序将在多个不同比例的多个位置使用MVC / MVP类型模式。您经常会发现,控制器/演示者可以方便地了解彼此并在它们之间进行通信,在这种情况下,您显然需要保留对控制器的引用。

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

答案 1 :(得分:0)

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

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

(所以,你永远不需要控制器的句柄 - 它的句柄总是与框架一起使用。)

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

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