【问题标题】:MVP and Package Cycle between view and presenterView 和 Presenter 之间的 MVP 和 Package Cycle
【发布时间】:2012-10-03 09:35:31
【问题描述】:

我刚刚参加了一个使用 GWT 和 MVP 设计的项目。它们使用以下结构:

client.mvp.presenter (contains interfaces)
client.mvp.presenter.impl
client.mvp.view (contains interfaces)
client.mvp.view.impl

在代码中,Presenter 知道它的视图,但视图也知道它的 Presenter,所以我在 Presenter.impl 和 view.impl 之间的包中找到了循环

再想一想,我问自己为什么impl 会链接自己,而不是只引用接口,从而避免循环。

但我也认为“为什么视图应该知道它的演示者?”并且查看一些谈论 MVP 的网站,如果视图和演示者应该相互了解,则不清楚。

什么是最好的?

  • 要求他们使用接口去除循环?
  • 要求从视图中删除 presenter 并让演示者直接处理用户交互?
  • 什么都不做,MVP 中的这些包之间通常有循环

谢谢!

【问题讨论】:

    标签: java gwt mvp


    【解决方案1】:

    实际上,虽然presenter impl [1] 现在需要视图(界面),但presenter 界面通常不需要。

    典型的模式是:

    interface FooPresenter {
       // methods called by the view (generally in response to user interaction)
       void doSomething(String foo);
    }
    
    interface FooView {
       /** Tells the view which presenter instance to call back. */
       void setPresenter(FooPresenter presenter);
    
       // methods called by the presenter to control the view
       void showSomething(String foo);
    }
    
    class FooPresenterImpl implements FooPresenter {
        private final FooView view;
    
        FooPresenterImpl(FooView view, /* other dependencies here */) {
           this.view = view;
        }
    
        // could also be the start() method of com.google.gwt.activity.shared.Activity
        public void init() {
           view.setPresenter(this);
        }
    
        // optional; could be called from onStop() and onCancel() if using Activity
        public void dispose() {
           view.setPresenter(null);
        }
    }
    

    其实我一般都是把presenter接口声明在view interface里面:

    interface FooView extends IsWidget {
    
        interface Presenter {
           // ...
        }
    
        void setPresenter(Presenter presenter);
    
        // ...
    }
    
    class FooPresenter extends AbstractActivity implements FooView.Presenter {
       // ...
    }
    

    Wrt impls 知道 impls,最重要的是演示者 impl 不会引用视图 impl,因为它(通常)会阻止在没有 GWTTestCase 的情况下对其进行单元测试(模拟视图)。反过来问题不大,但你真的不需要演示者界面与 impl,对吧?

    [1] 从技术上讲,它可能是视图 impl,但通常是相反的,因此视图可以比演示者更长寿(演示者通常是轻量级的,与视图相反,由于 DOM,视图可能具有不可忽略的创建时间操作)

    【讨论】:

      【解决方案2】:

      有了MVP,presenter和view需要知道对应的interfaces

      • 演示者通常需要更新视图
      • 当事件(例如 ValueChangeEvents)发生时,视图会调用演示者方法。

      请他们使用接口去除循环?

      是的。

      要求从视图中移除演示者并让演示者直接处理用户交互?

      不,那不会是 MVP。

      什么都不做,MVP 中的这些包之间通常有循环

      必然保留的循环是实例化循环:您不能将 演示者作为视图的构造函数参数 将视图作为构造函数参数主持人的。这在基于构造函数的依赖注入中变得尤为明显,并且在 Java 中理论上是不可避免的。但是您可以选择使用 setter(至少在一侧),或者使用带有构造函数注入的 factory/provider

      【讨论】:

      • “当事件发生时视图调用演示者方法”。查看 Google MVP 示例,似乎是演示者持有这部分:display.getList().addClickHandler,因此在他们的示例中,唯一的链接视图-->演示者是因为视图实现了 Presenter.Display 接口。
      • @Michael:是的,你也可以使用更紧密的耦合。在某些情况下,它可能是更好的解决方案。但是请注意 1.) 它仍然是调用演示者方法的视图(List 是视图的一部分)(clickHandler 是演示者中的匿名类),以及 2.) 较新的 MVP example contained in the activities and places docs 是如何不同的)
      • 也许换一种说法:在某种程度上,可以将 ClickHandler 视为只有一个演示者方法的迷你演示者。因此,2010 年 MVP 示例所做的不是调用view.setPresenter(PresenterInterface),而是调用view.getList().addClickHandler(ClickHandler)——这实际上有点违反Law of Demeter
      • 好吧,我太专注于模仿那些似乎有点过时的例子了。我会要求他们只使用接口来相互关联(视图/演示者),并将好的代码放在好的地方。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多