【问题标题】:GWT MVP UiBinder - passing arguments to the presenterGWT MVP UiBinder - 将参数传递给演示者
【发布时间】:2023-06-07 18:19:01
【问题描述】:

我已经开始了一个 GWT 项目,我决定尝试一下 UiBinder。我很难在 UiBinder 上放置 MVP 模式。

当我使用 GWT-pure-java 时:我会使用 Gin 为我的演示者注入相应的视图。这很简单,如果我想将 id 传递给 Presenter,那么我只需将 id 传递给 Presenter 的构造函数即可。

UiBinder 不是那么直接。我几乎可以肯定我遗漏了一些东西,因为很多人都声称 UiBinder 和 MVP 是天作之合……所以我希望在这个问题上得到一些可靠的回应 ;-)

我在几个简单的 GWT-UiBinder 示例中看到的是,视图是由活页夹创建的,然后:

  1. 视图在其构造函数中或通过@UIFactory 方法构造演示者。
  2. 对应的presenter被传递给视图(通过setter,不用说在视图构建之后)。

使用第一种方法,如果在视图中构建演示者,如何将 id 传递给演示者?你会做view.getPresenter().setId(42);,然后演示者会去服务器获取一些信息并要求视图显示它......闻起来很糟糕。

使用第二种方法,最终会得到一个非直观的对象图,其中不清楚谁是消费者,谁是生产者。此外,在视图需要来自演示者的信息的情况下(几乎所有用例都需要这个),我们会做什么:

//some code would create the presenter pass it the id and then call view.setPresenter
class MyView {
    void setPresenter(MyPresenter p) {
    this.presenter = p;
    //OK now that i have my presenter how do I ask it to fetch data from the server.
    //do i turn around and do: presenter.setView(this); and then the presenter takes 
    //over and uses the view to display the data?
     }
 }

这同样臭...对不起,很长的帖子,提前谢谢...

【问题讨论】:

    标签: gwt mvp uibinder


    【解决方案1】:

    自从我开始这个帖子并阅读回复以来已经有几天了。我已经决定了我的方法。我想我只是在这里提到它。

    再次感谢您深思熟虑的回复……他们很有帮助。

    正如 filip-fku 指出的演示者是主要实体,所以我决定在我的 mvp 对象的生命周期管理中继续威胁他们。换句话说,视图不会实例化演示者。演示者由其他演示者实例化(在某些时候我将委托给 Gin)。

    presenter 的builder 可以访问其对应的视图,并将视图注入到presenter(通过构造函数)。

    视图本身要么由builder 实例化,要么由UiBinder 实例化为更大视图的一部分。在 UiBinder 实例化视图的后一种情况下,父视图有一个 getter。下面是这种情况的一个例子:

    /*pojo for the parent ui-binder*/
    public class Form implements FormPresenter.View {
    @UiField PromptView namePrompt;
    @override
    PromptPresenter.View getNamePromptDisplay() {
        return namePrompt;  //introduced into this pojo via @UiField
    }
    //bunch of view code
    }//end of the class
    

    然后在 FormPresenter 中执行:

    private void buildNamePrompt() {
      new PromptPresenter(display.getNamePromptDisplay(), etc....);
    }
    

    我基本上使 mvp 生命周期类似于纯 java 方法。一旦我从中获得了一些好处,我会用 Gin 重构它。

    再次感谢。 附言如果您还没有看过上面提到的 i/o 演示文稿,那么值得一看。

    【讨论】:

      【解决方案2】:

      你说得对,让 View 引用它的 Presenter 并让 Presenter 引用 View 似乎有点不干净。

      我的看法,以及关于 MVP 的谷歌开发页面如何概述 MVP 有两种风格:

      1. 拥有一个不知道其演示者的视图,并用演示者“包装”它。该视图为演示者提供了足够的 API 来获取/设置它关心的所有数据。此外,演示者必须了解视图可以生成的所有事件类型,以便响应用户交互。这是MPV part 1的方法。
      2. 演示者再次了解视图,但这次仅在获取/设置数据容量中。演示者不关心视图中的 UI 事件。相反,presenter 为视图提供了一个 API,以便在我们的 Presenter 中以“onSomethingHappened()”方法的形式发生事件时调用/通知它。这使我们能够捕获演示者本身中的所有行为/逻辑,并在视图中发生某些事情时根据需要调用它。然后,视图可以以任何合适的方式处理非常低级别的事件 - 无论是使用 GWT 事件/小部件还是使用元素/HTML 的原始 DOM 事件(UiBinder/GWT 性能最佳实践)。这是MVP part 2的方法。

      我更喜欢选项 2,因为它允许演示者完全专注于必要的行为。视图可以根据需要处理小部件/html/事件处理,并将其简化为对演示者的“onSomething()”调用。这些小部件/事件实现可能是简单或复杂且经过优化的事件。演示者不受详细信息的影响(也未污染),因为它只是收到通知。我觉得这个选项更清晰地分离了表现和行为。注意它也是Observer Pattern的一对一实现,所以View和Presenter之间的互连是必要的。

      至于创作,我觉得 Presenter 是一个更强大的实体,尽管它扮演着 Observer 的角色。我会创建必要的演示者,然后将关注的视图传递给它。演示者然后可以控制视图,并将视图传递给自引用。

      至于您的生产者/消费者类比,我认为演示者是消费者。视图产生 UI 事件(用户交互),演示者通过提供必要的行为进行响应。那应该是视图和演示者之间的唯一联系点 - 视图调用诸如“onSomethingHappened()”之类的方法,并且演示者完成工作。视图永远不会告诉演示者“fetchData()”或类似的东西。

      我自己最近才开始使用 UiBinder + MVP,所以这正是我的想法。希望对你有帮助!

      【讨论】:

      • 另见google.com/events/io/2010/sessions/…,其中讨论了他们如何在 Google Wave(现在的 Apache Wave)中使用 MVP:演示者从不 gets 到视图,相反,视图总是用适当的值;演示者完全控制演示状态。虽然它不能很好地与编辑器框架和/或单元格小部件一起使用,但它是一种有趣的方法。
      • 感谢您的周到回复...我已经研究了文章和附件示例。我还没有看过wave session(我稍后会看)。我从来没有真正使用过 display.getClickHandler 方法(即使我使用了 gwt-pure-java)。我总是有二传手(display.setClickHandler)。我需要进一步考虑这一点。我可能没有考虑 UiBinder 及其在正确创建视图和放置视图中的作用......