Model-View-Presenter中的Presenter是否会创建视图?

时间:2011-06-06 07:36:25

标签: theory mvp architectural-patterns

如何在MVP中创建视图? Presenter是否始终创建它们(除了子视图的视图外)?或者它是一个单独的第三方组件或应用程序或创建它们的东西?

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

所以,我有这些代码行:

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

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

5 个答案:

答案 0 :(得分:45)

这取决于......

MVP的主要目标是将复杂的决策逻辑与UI代码分开,使其变得更容易理解和维护。通常另一个目标是使演示者的决策逻辑可测试。

Fowler在2004年描述了MVP模式,他retired it in 2006将模式分为Supervising Conroller(SC)和Passive View(PV)。在SC中,View与模型绑定,但在PV中不绑定;在PV中,View只能由Presenter直接更改。

在SC和PV中,演示者必须更新视图对用户对视图所做的更改做出反应,例如输入文本或按下按钮。当您在Presenter上使用View调用方法时,会出现您描述的问题,因为View需要对Presenter的引用,反之亦然。如果您这样做,您只需决定谁将其全部启动。选项包括:

  1. View创建Presenter的实例。加载View时,它会在Presenter的初始化函数中将自身传递给Presenter。
  2. 反过来说:Presenter创建View并在View的初始化函数中将自身传递给View。
  3. 您介绍了第三个创建View和Presenter的对象,将它们连接在一起并初始化它们。
  4. 所有选项都可以让您达到关注点分离和决策逻辑可测性提高的“MVP目标”。我不认为这些方法中的任何一种在理论上是正确的或错误的 - 您只需选择最适合您使用的技术的方法。在整个应用程序中,最好保持一致的选择。

答案 1 :(得分: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 = cvpParamthis.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中,似乎可以更容易地进行测试。

两个很好,因为你不必过多关心演示者,并且可以更多地担心你的观点。

答案 2 :(得分:2)

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

答案 3 :(得分: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;
  }
}

答案 4 :(得分:0)

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

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

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