【问题标题】:Does Presenter in Model-View-Presenter create views?Model-View-Presenter 中的 Presenter 是否创建视图?
【发布时间】:2011-09-09 02:11:07
【问题描述】:

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

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

所以,我有这些代码行:

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

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

【问题讨论】:

    标签: theory mvp architectural-patterns


    【解决方案1】:

    如果您使用的是 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;
      }
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 当您选择让视图和演示者相互引用时,使用 IOC 框架对非单例视图和演示者没有帮助。
      • 话虽如此,让第三个组件实例化“mvp 三元组”会很有帮助,例如,如果您想拦截对查看和演示者的调用。
      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

        这取决于...

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

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

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

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

        所有选项都可以让您实现关注点分离和决策逻辑可测试性提高的“MVP 目标”。我认为这些方法中的任何一种在理论上都没有对错——您只需选择最适合您使用的技术的方法即可。最好在整个申请过程中保持一致。

        【讨论】:

        • 我想补充一些例子,但我不太擅长 Javascript,对不起,
        • 感谢您的想法。在任何地方都很难找到有关这些问题的信息。我想我倾向于第三种选择。我必须计划一下,看看它是否有效。你有什么好的资源/链接可以分享吗?
        • 昨天我做了一个快速的google search。我发现this SO question 读起来很有趣。
        • 除了我的答案中的链接,我发现build-your-own-cab-series 非常适合解释 MVP 的不同风格。但它是特定于 .NET 的。
        • 我得出的结论是,我将在 MVP 三元组之外实例化 Presenter 和 View。我还没有决定哪个应用程序组件应该负责这样做。但是,View 不会知道 Presenter。 View 将触发 Presenter(知道 View)可以捕获并采取行动的事件。 Presenter 还会监听 Model 事件并在需要时重新渲染 View。
        【解决方案5】:

        这些是您的选择:

        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 中,并且似乎可以更轻松地进行测试。

        Two 很好,因为您不必过多关心 Presenters,而可以更多地担心您的 Views。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多