2008-10-09 293 views
11

使用MVP,构造和依赖注入的正常顺序是什么。MVP依赖注入

通常情况下,您为每个视图创建一个演示者,并将该视图传递给构造函数上的演示者。但是如果你有:

  1. 多个视图需要监听事件的服务。
  2. 多个视图都指向相同的数据模型缓存。

有人可以显示正常的信息流从用户点击到数据从服务器返回服务。

回答

12

这里是我做的:

首先,我定义论文的接口:

public interface IView<TPresenter> 
{ 
    TPresenter Presenter { get; set; } 
} 

public interface IPresenter<TView, TPresenter> 
    where TView : IView<TPresenter> 
    where TPresenter : IPresenter<TView, TPresenter> 
{ 
    TView View { get; set; } 
} 

那么这个抽象主持人类:

public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter> 
    where TView : IView<TPresenter> 
    where TPresenter : class, IPresenter<TView, TPresenter> 
{ 
    protected TView view; 

    public TView View 
    { 
     get { return this.view; } 
     set 
     { 
      this.view = value; 
      this.view.Presenter = this as TPresenter; 
     } 
    } 
} 

视图是通过属性注入,而不是的构造函数,以允许setter中的双向感情。请注意,需要一个安全的投...

然后,我的具体演讲是一样的东西:

public class MyPresenter : AbstractPresenter<IMyView, MyPresenter> 
{ 
    //... 
} 

IMyView实现IView。一个具体的视图类型必须存在(例如MyView),但它的解析它的容器:

  1. 我寄存器MyPresenter类型本身在容器中,具有瞬态行为。
  2. 我注册为MyView作为IMyView在具有瞬态行为的容器中。
  3. 我然后要求容器上有一个MyPresenter
  4. 容器实例化一个MyView的
  5. 它instanciates一个MyPresenter
  6. 它通过AbstractPresenter.View属性注入视图到主持人。
  7. 的二传手代码完成双向关联
  8. 容器返回夫妇演示/查看

它可以让你注入其他依赖(服务,回购)到两个视图和您的主持人。但是,在您描述的情况下,我建议您将服务和缓存注入主讲人,而不是视图。

+1

你是如何处理IDisposable的顾虑吗?特别是,打破循环引用以允许垃圾收集? – aboy021 2013-04-29 02:48:39

7

在WinForms中,我更喜欢简单的方法。通常你在设计表面上处理几个UserControls - 使这些视图类成为你的视图类。 .NET为您创建控件层次结构(通过InitializeComponent)。如果您使用Passive View模式,则每个视图会实例化其演示者。 (您可以直接或通过询问IOC容器来做到这一点。)使用构造函数注入将视图的接口的引用传递给演示者的构造函数。演示者然后可以连线自己查看事件。重复模型的过程:演示者实例化一个模型并连接到它的事件。 (在这种情况下,你不需要构造函数注入,因为被动视图说主持人保持对模型的引用,而不是反之亦然。)

我发现这种方法唯一的缺点是正确管理模型和主持人。您希望保持视图尽可能简单,所以您可能不希望它保持对演示者的引用。但是,这意味着您已将此演示者对象与视图绑定的事件处理程序挂在一起。此设置可防止您的视图被垃圾收集。一种解决方案是让你的视图发布一个事件,表明它正在关闭。演示者将收到该事件并删除其模型和查看订阅。您的网络中的对象现在已正确解除引用,垃圾收集器可以继续其工作。

你风的东西,如下列:

public interface IView 
{ 
    ... 
    event Action SomeEvent; 
    event EventHandler Disposed; 
    ... 
} 

// Note that the IView.Disposed event is implemented by the 
// UserControl.Disposed event. 
public class View : UserControl, IView 
{ 
    public event Action SomeEvent; 

    public View() 
    { 
     var presenter = new Presenter(this); 
    } 
} 

public interface IModel 
{ 
    ... 
    event Action ModelChanged; 
    ... 
} 

public class Model : IModel 
{ 
    ... 
    public event Action ModelChanged; 
    ... 
} 

public class Presenter 
{ 
    private IView MyView; 
    private IModel MyModel; 

    public Presenter(View view) 
    { 
     MyView = view; 
     MyView.SomeEvent += RespondToSomeEvent; 
     MyView.Disposed += ViewDisposed; 

     MyModel = new Model(); 
     MyModel.ModelChanged += RespondToModelChanged; 
    } 

    // You could take this a step further by implementing IDisposable on the 
    // presenter and having View.Dispose() trigger Presenter.Dispose(). 
    private void ViewDisposed(object sender, EventArgs e) 
    { 
     MyView.SomeEvent -= RespondToSomeEvent; 
     MyView.Disposed -= ViewDisposed; 
     MyView = null; 

     MyModel.Modelchanged -= RespondToModelChanged; 
     MyModel = null; 
    } 
} 

您可以通过使用国际奥委会和要求IModel的实现您的IOC容器(在演示类)和IPresenter一步脱钩这个例子( View类)。

0
interface IEmployee 
{ 
    int EmployeeId {get;} 
    string FirstName {get;} 
    string LastName {get;} 
} 
interface IEmployeeRepository 
{ 
    void SaveEmployee(IEmployee employee); 
    IEmployee GetEmployeeById(int employeeId); 
    IEmployee[] Employees { get; } 
} 
interface IEmployeeView 
{ 
    event Action<IEmployee> OnEmployeeSaved; 
} 

interface IEmployeeController 
{ 
    IEmployeeView View {get;} 
    IEmployeeRepository Repository {get;} 
    IEmployee[] Employees {get;}   
} 

partial class EmployeeView: UserControl, IEmployeeView 
{ 
    public EmployeeView() 
    { 
     InitComponent(); 
    } 
} 
class EmployeeController:IEmployeeController 
{ 
    private IEmployeeView view; 
    private IEmployeeRepository repository; 
    public EmployeeController(IEmployeeView view, IEmployeeRepository repository) 
    { 
     this.repository = repository; 
     this.view = view; 
     this.view.OnEmployeeSaved+=new Action<IEmployee>(view_OnEmployeeSaved); 
    } 

    void view_OnEmployeeSaved(IEmployee employee) 
    { 
     repository.SaveEmployee(employee); 
    } 
    public IEmployeeView View 
    { 
     get 
     { 
      return view; 
     } 
    } 
    public IEmployeeRepository Repository 
    { 
     get 
     { 
      return repository; 
     } 
    } 

    public IEmployee[] Employees 
    { 
     get 
     { 
      return repository.Employees; 
     } 
    } 
} 
+2

能否请您评论你的代码? – 2012-10-28 00:14:47