4

我正在尝试学习 MVP,但有些东西让我无法理解;如果 Presenter 使用视图作为界面,那么 View 就不能只是控件的简单渲染。想象一下,尝试编写一个打字练习游戏,其中单词随机生成到 UI 中,用户必须在单词落下时输入。

所以视图将有如下方法:

public interface View {
    addWord(String word, double x, double y); // or possibly (Word word)
    moveWord(String word, double distance);
    removeWord(String word);
    setScore(int score);
    registerKeyListener(KeyListener listener);
    // other stuff
}

但最终 VIEW 将不得不负责创建自定义控件。这里省略了很多代码,但希望这足以说明我的意思。例子:

public class SwingView {
    private JPanel thePanel;

    private Map<String, WordComponent> currentWords = new HashMap<>();

    public SwingView() {
        thePanel = new JPanel(new WordLayout());
        // other stuff
    }

    public void addWord(String word, double x, double y) {
        WordComponent newWord = new WordComponent(word);
        currentWords.put(word, newWord);
        Point2D.Double point = new Point2D.Double(x, y);
        thePanel.add(newWord, point);
    }

    public void removeWord(String word) {
        WordComponent theWord = currentWords.get(theWord);
        thePanel.remove(theWord);
    }
}

View 实现已经有逻辑了。它保持着它的Map一个WordComponent。我在这里有两个我自己的类WordLayout implements LayoutManager2,和WordComponent extends JLabel(或其他东西,但那将是更多的代码)。

从理论上讲,演示者应该对 Swing 一无所知,因此我可以使用可能会记录到控制台或其他东西的模拟进行单元测试。但简单地管理 Swing 对象本身就是一项工作。或者,如果我想将此应用程序转换为 Tomcat 网页怎么办。现在类ServletView正在管理移动单词的 AJAX 调用。它依赖于 AJAX 框架,将更多工作卸载到View.

摘要:View实现是否应该具有管理自己的组件的“逻辑”?

跟进:我上面写的代码可能甚至不会响应,因为ModelPresenter不在 Event Dispatch 线程上工作(或者,他们是,这可能更糟)。将显示更新传递给 Event Dispatch 线程的代码在哪里?或者,应该Presenter在事件调度线程上吗?

编辑:我刚刚想到一个想法。拥有一个特定于平台的子演示者,该子演示者了解实现细节,例如您使用的是 Swing 还是其他东西。

Edit2:还有一个问题,基于@DuncanJones 的回答。想象一下,我想加入逻辑以使游戏可调整大小并根据新大小调整所有内容的大小。该逻辑会在 中View,还是在 中Presenter

4

2 回答 2

4

View 组件必须包含足够的逻辑来向用户显示界面。根据使用的框架,视图中可能有相当多的代码。重要的是确保业务逻辑位于 Presenter 中。

关于您的辅助查询,当视图调用它们时(在 Swing 的情况下),所有 Presenter 方法都将在 EDT 上被调用。除非 Presenter 要求的操作是微不足道的,否则我会立即启动一个后台线程来完成工作。该线程将在使用完成后更新视图SwingUtilities.invokeLater()

事实上,为了避免与 Swing 绑定,我倾向于将自己的EventDispatcher课程传递给每个 Presenter。这是一个与 具有相同方法的接口SwingUtilities。如有必要,我可以换成不同的班级。

旁注:这会使使用 JUnit 对 Presenter 进行单元测试变得困难,因为 Presenter 方法(和单元测试)将在后台线程之前完成。我倾向于使用Executor负责运行后台线程的每个 Presenter 来构建每个 Presenter。然后,在单元测试环境中,我传入一个特殊的Executor实现,它会立即run()在同一个线程上执行该方法。这确保了单元测试是单线程的。例子:

public class SingleThreadExecutor implements Executor {
  @Override
  public void execute(Runnable command) {
    command.run();
  }
}
于 2013-07-24T14:20:06.147 回答
0

MVP 模式的不同风格的重点是将业务逻辑与视图逻辑分离。考虑到这一点,拥有一个包含大量显示逻辑的视图是完全可以的。但是有一些警告:

不要将您的小部件用作数据存储。小部件的目的是呈现内容或接收输入。演示者和模型负责保持状态。如果视图是有状态的,演示者应该意识到它并协调它。例如,窗口大小在大多数情况下是视图的关注点。但是,如果要将其持久化到某些用户设置文件中,则必须涉及演示者。

不要求视图是一个单一的整体类。只需要一个对象实现演示者期望的接口,并且有人生成事件。例如,Swing 使用 TableModel 之类的组件,其中可以放入用于指定数据表示的代码。此外,JavaFX 和 Android 可以减少大量样板代码来设置视图。

当然,事件必须在正确的线程中处理。您可以使用可以被告知做正确事情的事件总线,或者将 ExecutorService 传递给每个视图。此外,演示者调用的每个方法都必须将工作卸载到框架的首选线程。最好不要让演示者担心,否则将变得难以测试。正确的事情取决于框架。

于 2017-04-19T10:24:29.010 回答