【问题标题】:MVC many view and one controllerMVC多视图一控制器
【发布时间】:2012-02-16 21:10:02
【问题描述】:

在我的应用程序中,有许多视图(子组件)并且只有一个控制器。在一个视图中选择某些选项可以更改另一个视图中的布局和组件数量。 控制器初始化视图,然后创建所有子组件。

在这样的应用程序中,控制器是否需要引用所有子组件? 正如在一个视图中的侦听器中调用控制器来执行操作,然后需要更新另一个视图。 我觉得控制器不应该有对所有视图的引用,但不知道从哪里形成这里。 Head first design patterns book 中的示例只有一个视图,所以我被卡住了。

++++++++++++++++++++++++++

更多细节。 我正在写的游戏是跳棋(选秀)游戏。在一种情况下,当计算机与自己对战时,用户必须在游戏开始前选择一些选项。一种这样的选择是在游戏期间选择特定时期的游戏策略。比如当它有12到8个棋子时,它会攻击更多,当它有8到4个棋子时,它会更防守。

目前游戏 GUI 的结构方式是有一个整体 JPanel (RightContainerFrame),其中包含其他 JPanel;然后有一个 JPanel (StartGamePanel),用户可以在其中配置游戏。还有一个包含选项卡的 JTabbedPane (jTabbedPane1)。目前在 StartGamePanel 中,当用户在 JComboBox 中选择某个选项时,需要在 jTabbedPane1 中添加或删除选项卡。

我目前实现这一点的方式是在 StartGamePanel 中

RightContainerFrame.getInstance().generateAndDisplayPlayerTwoRangeTabs(numberOfRangeTabsNeeded);

现在我知道这都是错误的,因为我有一个视图,StartGamePanel 通过调用另一个容器视图 RightContainerFrame 中的方法直接更改另一个视图 JTabbedPane。

我愿意接受有关如何构建此问题的任何建议。

首先,我可以将jComboBox1ActionPerformed 方法移至控制器。这可以更新 jTabbedPane1 的模型。或者它可以直接在 jTabbedPane1 中调用一个方法来显示所需的选项卡数。

【问题讨论】:

  • 当您说“许多视图”时,我通常会想到许多不同的 GUI,每个 GUI 都以不同的方式显示信息。如果您不是这个意思,但另一方面意味着有一个 GUI(一个视图)在不同部分显示数据的不同部分,那么答案会有所不同。请说清楚。如果是后者,那么控件只需要对主视图的引用,但这需要公共方法,以便控件可以更改其状态,并且视图可以响应这些状态更改。
  • 我的意思是一个 GUI 有很多 JPanel,一个 JPanel 中的选择会影响其他 JPanel 中显示的信息。主视图会引用所有子组件吗?
  • 什么是主视图?控制器?
  • 在我的版本中,在控制器构造函数中创建视图。然后,此视图创建所有子组件。所以这是正确或错误的主要观点。 public Controller() { ... this.gameView = new GameView(this);
  • 除了你应该努力“最大限度地提高内聚力并最大限度地减少耦合”之外,我不知道任何一刀切的答案,但这似乎是最好的。我尽量让我的观点变得愚蠢,让我的模型尽可能地不了解观点和控制。如需更具体的建议,您可能需要告诉我们更多细节并发布您的代码。

标签: java swing design-patterns


【解决方案1】:

Swing 不是真正的 MVC 架构:它是一个模型/(视图+控制器)architecture。每个 JComponent 既是视图又是控制器。

您需要定义与组件上的某些事件相关联的回调方法(也称为事件侦听器)。针对不同 JComponent 上的不同类型事件,有不同类型的事件侦听器。

这是一个在按钮上注册事件侦听器的示例,当单击它时,它会更改另一个组件 (myJLabel) 中的文本:

jButton1.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent event) {
        myJLabel1.setText("You just clicked a button.");
    }
}
// you can add other ActionListeners to the same jButton1

您可以拥有一个处理所有事件的全局控制器,但您需要将其注册为每个组件的侦听器。当全局控制器收到event 时,它可以查询它以找出它来自哪个按钮并相应地更改其他 JComponent(s)。所以,是的,你的全局控制器需要对所有 JComponents 的引用,除了作为侦听器注册到所有 JComponents 之外。全局控制器不仅需要实现上述的 ActionListener 来获取鼠标点击,还需要实现处理来自其他组件的所有其他类型的事件所需的所有其他类型的 EventListener。

拥有一个全局控制器可能不是一个好主意,因为它最终可能会成为一个非常大的类。只需让每个 JComponent 注册一个(或多个)直接更改其他组件的事件侦听器就足够了。

编辑
我不太确定拥有一个全局控制器是不是一个坏主意:你最终会得到一个巨大的类,但至少所有回调逻辑都在一个地方。

【讨论】:

  • 感谢我最初写它的方式改变了其他观点。应避免从阅读视图更改其他视图,但这似乎也是最简单的方法。
  • 无论有没有全局控制器,它都很混乱......我不确定哪个是最好的。我认为没有一种非常干净的方式来处理回调函数。我很高兴看到其他人的意见。
【解决方案2】:

我还不知道视图如何更新其他视图。

这个简单的example 说明了observer pattern,它让model 更新view 以响应controller查看 动作。这个更精细的example 显示了三个view 正在监听一个model

【讨论】:

  • 只是与我的回答相关的评论:在您的示例中,您没有将所有控制处理都放在控制器中。 PieceButtons 的 ButtonHandlers 仍然是 View 而不是 Control 的一部分。您可以让 Control 实现 ActionListener 并将其注册到 PieceButtons 并让它修改模型并更新视图。
【解决方案3】:

老实说,我无法清楚地理解您的设计,但在这种情况下我会采用的设计(假设我们谈论的是基于丰富组件的 UI 技术)是让 Views 监听事件总线并调整自己的根据在公共汽车中过境的事件进行布局。在这种情况下,UI 操作处理程序可能会在总线中发布事件。有效地将视图彼此以及与控制器解耦。

更新:看看here - 作为谷歌的东西往往有点书呆子和过度设计,以满足大多数中低复杂度的需求,但您可以将其精简以适应您的需求。

【讨论】:

  • 我的设计是视图观察模型。控制器处理视图创建的事件。我还不知道视图如何更新其他视图。
  • 好吧,我认为您别无选择,只能让控制器知道所有视图。我认为这不是最佳维护方式,但这是您的决定。
  • 我不喜欢这个设计。是否有 Java 中的设计模式或类可用于实现事件总线?
猜你喜欢
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
相关资源
最近更新 更多