MVP:是应该知道模型的View还是Presenter?

naw*_*fal 6 mvp design-patterns winforms

相对较新的模式,让我直接在WinForms的上下文中展示一个例子.

我有一个基本的MVP被动视图结构,我应该继续:

public partial class UserView : Form, IUserView
{
    public event EventHandler Save;

    public UserView()
    {
        InitializeComponent();

        new UserPresenter(new UserModel(), this);
    }
}

public class UserPresenter
{
    public UserPresenter(IUser model, IUserView view)
    {
        view.Save += (sender, e) => model.Save();
    }
}
Run Code Online (Sandbox Code Playgroud)

要么

public partial class UserView : Form, IUserView
{
    public event EventHandler Save;

    public UserView()
    {
        InitializeComponent();

        new UserPresenter(this);
    }
}

public class UserPresenter
{
    public UserPresenter(IUserView view)
    {
        var model = new UserModel();
        //assuming I have the logic to bind property values from View to Model
        view.Save += (sender, e) => model.Save();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

1)谁应该知道模型User,View或Presenter 的具体实例?

2)在这种情况下会有什么好处?

3)假设我的模型永远不依赖于视图.在那种情况下,如果View知道Model有什么问题?毕竟UserView是出现在现在UserModel不是吗?

4)如果Presenter只与Model和View的接口交互,那么model.SaveSaveeventhandler 中调用,我从哪里获取具体的实例Model

这里这里有两个重复的问题,但它们并不完全处理我的场景我猜...

Bob*_*Bob 17

严格来说,您应该遵守以下规则:

  1. 模型不知道视图或演示者.
  2. View不知道Model或Presenter.
  3. Presenter知道模型和视图,但只能通过它们的接口.

Presenter通常通过处理View引发的事件来协调Model和View之间的所有通信.那么回答你的问题:

1)谁应该知道模型User,View或Presenter的具体实例?

理想情况下,都不是.Presenter应该通过IUserModel接口与UserModel通信.具体实例被注入Presenter(例如通过其构造函数).

2)在这种情况下会有什么好处?

主要好处是自动化单元测试.您可以单独注入模拟模型或视图来测试单元.

3)假设我的模型永远不依赖于视图.在那种情况下,如果View知道Model有什么问题?毕竟UserView是为了呈现UserModel不是吗?

它没有任何内在错误.MVP的变体支持从View到Model的直接通信,通常是利用数据绑定.您将失去一些可测试性,以换取不必从头开始编写绑定代码.

4)如果Presenter只与Model和View的接口交互,那么在Save eventhandler中调用model.Save,从哪里获取Model的具体实例?

依赖注入,如下面所示的简化示例.

public class SamplePresenter
{
     public SamplePresenter(ISampleModel model, ISampleView view)
     {
          view.Saved += (sender, e) => model.Save();
     }
}

public interface ISampleModel
{
     void Save();
}

public interface ISampleView
{
     void Show();
     event EventHandler Saved;
}

public class Program
{
     [STAThread]
     static void Main()
     {
          ISampleModel model = new SampleModel();
          ISampleView view = new SampleView();
          SamplePresenter presenter = new SamplePresenter(model, view);
          view.Show();
     }
}
Run Code Online (Sandbox Code Playgroud)

  • MVP黑社会外部的东西.在上面的例子中,我只是在Main方法中这样做了.您可以考虑使用某种IoC容器. (2认同)

Big*_*ddy 7

如果视图知道模型有什么问题?毕竟UserView是专门为UserModel制作的吗?

没有.它是Supervising ControllerMVP模式变体中的公认惯例.视图直接与模型交互以进行简单操作,而更复杂的操作则通过演示者进行编组.在进入时Passive View,一切都通过演示者.

此外,请参阅Jeremy Miller的构建您自己的CAB系列,以更好地了解两种方法之间的差异:监督控制器被动视图.

  • @nawfal:在一个项目中拥有演示者和视图仍然允许您独立于视图单独测试演示者,这是MVP的全部要点.无论如何,视图界面和演示者应该组织在文件夹中,因此在需要时重构为单独的项目(例如,更改视图引擎)并不困难.从一开始就单独执行项目的一个原因是,保持引用清洁更容易,这样就不会在演示者中开始使用特定于视图的代码(例如`System.Web`). (2认同)