31

在 MVP 中如何创建视图?演示者是否总是创建它们(除了在子视图的情况下查看)?或者它是一个单独的第三方组件或应用程序或创建它们的东西?

我们还要补充一点,我可能会在 Dojo Toolkit/ExtJS(即 JavaScript)上执行此操作。

所以,我有这些代码行:

var v = new MyApp.view.User();
var p = new MyApp.presenter.User();

两条线到底应该去哪里?演示者是否实例化视图,反之亦然?什么实例化了第一个实例?

4

5 回答 5

49

这取决于 ...

MVP 的主要目标是将复杂的决策逻辑从 UI 代码中分离出来,以便更容易理解和维护。通常另一个目标是使演示者中的决策逻辑可测试。

MVP 模式由 Fowler 在 2004 年描述,他在 2006 年将其拆分为监督控制器(SC) 和被动视图(PV)。在 SC 中,View 与 Model 绑定,但在 PV 中没有;在 PV 中,View 仅由 Presenter 直接更改。

在 SC 和 PV 中,Presenter 必须更新 View并对用户对 View 所做的更改做出反应,例如输入文本或按下按钮。当您让 View 调用 Presenter 上的方法时,就会出现您描述的问题,因为 View 需要对 Presenter 的引用,反之亦然。如果您这样做,您只需决定由谁来启动它。选项是:

  1. View 创建 Presenter 的一个实例。当 View 被加载时,它会在 Presenter 上的一个初始化函数中将自己传递给 Presenter。
  2. 反过来:Presenter 创建 View 并在 View 的初始化函数中将自身传递给 View。
  3. 您引入了创建 View 和 Presenter 的第三个对象,将它们连接在一起并初始化它们。

所有选项都允许您达到关注点分离和决策逻辑可测试性增加的“MVP 目标”。我认为这些方法中的任何一种在理论上都没有对错——您只需选择最适合您使用的技术的方法即可。最好在整个应用程序中保持一致。

于 2011-06-21T19:57:50.760 回答
6

这些是您的选择:

var cvp = new ContactViewPresenter(new ContactView());

ContactViewPresenter构造函数集this.view = viewParam和集合this.view.presenter = this。它将代码保存在 Presenter 中,必要时可以交换视图,并且可以传入视图的模拟以进行测试。

var cv = new ContactView(new ContactViewPresenter());

ContactView构造函数集this.presenter = cvpParam, 和this.presenter.view = this. View中的一些逻辑,但不是很多。如有必要,可以更换演示者。

ContactView cv = new ContactView();
ContactViewPresenter cvp = new ContactViewPresenter();
cv.presenter = cvp;
cvp.view = cv;
cv.init();
cvp.init();

这是更多的代码。

ContactViewPresenter cvp = new ContactViewPresenter();

构造函数创建集合this.view = new ContactView()this.view.presenter = this

ContactView cv = new ContactView();

构造函数集this.presenter = new ContactViewPresenter()this.presenter.view = this

最后两个似乎有点太耦合了。

一个很好的地方在于代码保留在 Presenter 中,并且似乎允许更轻松的测试。

二是很好,因为您不必过多关心演示者,并且可以更多地担心您的视图。

于 2012-05-20T19:09:37.220 回答
2

我不认为 Presenter 应该实例化视图,这应该由 MVP 三元组之外的实体(不是面向数据的意义上,我的意思是一般实体)来完成。例如,一个控制反转 (IoC) 框架(如果您还没有听说过 IoC,请查看Martin Fowler 的文章),或者一些负责用户配置的应用程序模块。

于 2011-06-19T22:19:39.883 回答
0

我的术语可能略有错误,但我认为您需要确定互动的构成根源;开始互动的东西是什么?

在我给出的 Webforms 示例中,Webform 由 Http 管道创建,OnInit 或 OnLoad 事件是管道中的第一个点(取决于您需要的上下文),您可以“挂钩”到流程中。因此,您创建了一个 Presenter 并将您的 Webform 的具体实例作为视图接口提供给它。

我不知道您正在讨论的 Javascript 框架,但我认为有一个初始化/调用步骤 - 在 ASP.NET MVC 中,这是涉及 ActionInvoker 的时候,它是控制台应用程序中的 Main。

于 2011-06-21T15:37:15.787 回答
0

如果您使用的是 WebForms,那么 WebForm OnLoad 或 Init 应该是您创建 Presenter 的地方 - 然后将接口引用传递给 WebForm 实现的 View。

所以,像这样:

Presenter _presenter;

OnLoad(object sender, EventArgs e) 
{
  _presenter = new Presenter(this);
  _presenter.Initialise();
}

Presenter 构造函数是这样定义的:

public class Presenter
{
  public Presenter(IView viewReference)
  {
    _viewReference = viewReference;
  }
}
于 2011-06-06T08:19:08.353 回答