就像每个人都说过的那样,这里有数十种观点,而且没有一个是对还是错。在不涉及多种模式的情况下,仅关注MVP,这里有一些实施建议。
将它们分开。视图应该实现一个接口,该接口形成视图和演示者之间的纽带。视图创建了一个演示者,并将其自身插入到演示者中,并公开了它为演示者提供的与视图交互的方法。视图负责以其希望的任何方式实现这些方法或属性。通常,您有一个视图:一个演示者,但在某些情况下,您可以有多个视图:一个演示者(Web,WPF等)。这里的关键是演示者不知道UI实现,只能通过界面与视图交互。
这是一个例子。首先,我们有一个带有简单方法的视图类,用于向用户显示消息:
interface IView
{
public void InformUser(string message);
}
现在是主持人。请注意,演示者将IView纳入其构造函数。
class Presenter
{
private IView _view;
public Presenter(IView view)
{
_view = view;
}
}
现在是实际的用户界面。可能是窗口,对话框,网页等。没关系。请注意,视图的构造函数将通过将自身注入演示者来创建演示者。
class View : IView
{
private Presenter _presenter;
public View()
{
_presenter = new Presenter(this);
}
public void InformUser(string message)
{
MessageBox.Show(message);
}
}
演示者不在乎视图如何实现它所执行的方法。对于演示者所知,它可能正在写入日志文件,甚至没有向用户显示。
无论如何,演示者都会在后端使用模型进行一些工作,并且有时希望将发生的事情告知用户。因此,现在演示者中的某处有一个方法可以调出视图InformUser消息。
class Presenter
{
public void DoSomething()
{
_view.InformUser("Starting model processing...");
}
}
这是您去耦的地方。演示者仅持有IView的实现参考,并不真正在意它的实现方式。
这也是一个糟糕的实现,因为您确实在视图中引用了Presenter,并且对象是通过构造函数设置的。在更强大的解决方案中,您可能希望查看控制反转(IoC)容器,例如Windsor,Ninject等,这些容器将在运行时按需为您解决IView的实现,从而使其更加分离。