MVP中如何创建视图?演示者是否总是创建它们(在子视图的情况下,除了视图之外)?还是一个单独的第三方组件或应用程序或创建它们的东西?
让我们补充一点,我可能会在DojoToolkit/ExtJS(即JavaScript)上执行此操作。
所以,我有这些代码行:
var v = new MyApp.view.User();
var p = new MyApp.presenter.User();
这两条线到底应该去哪里?演示者是否实例化视图,反之亦然?是什么实例化了第一个实例?
这取决于。。。
MVP的主要目标是将复杂的决策逻辑从UI代码中分离出来,使其更易于理解和维护。通常,另一个目标是使演示者的决策逻辑可测试。
Fowler在2004年描述了MVP模式,并于2006年将其分解为监督Conroller(SC)和被动视图(PV)。在SC中,视图绑定到模型,但在PV中不绑定;在PV中,视图仅由演示者直接更改。
在SC和PV中,演示者都必须更新视图,并且对用户对视图所做的更改做出反应,例如输入文本或按下按钮。如果让视图调用Presenter上的方法,则会出现您所描述的问题,因为视图需要对Presenter的引用,反之亦然。如果你这样做,你只需决定谁来启动这一切。选项包括:
- "视图"将创建Presenter的实例。加载视图后,它会在Presenter上的初始化函数中将自己传递给Presenter
- 另一种方法是:Presenter创建"视图",并在"视图"上的初始化函数中将其自身传递给"视图"
- 您将引入第三个对象,该对象将创建View和Presenter,将它们连接在一起并对它们进行初始化
所有选项都允许您实现"MVP目标",即分离关注点和提高决策逻辑的可测试性。我不认为这些方法在理论上是对的或错的–;你只需要选择一个最适合你使用的技术。在整个应用程序中,您的选择最好保持一致。
以下是您的选项:
var cvp = new ContactViewPresenter(new ContactView());
ContactViewPresenter
构造函数设置this.view = viewParam
,并设置this.view.presenter = this
。它将代码保存在Presenter中,必要时可以交换视图,还可以传入视图的mock进行测试。
var cv = new ContactView(new ContactViewPresenter());
ContactView
构造函数集合this.presenter = cvpParam
和this.presenter.view = this
。有一些逻辑,但不是很多。如有必要,可以更换演示者。
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中,并且似乎允许更容易的测试。
第二个很好,因为你不必太关心演示者,也可以更担心你的视图。
我认为Presenter不应该实例化视图,这应该由MVP三元组之外的实体(不是面向数据的意义上的,我指的是通用实体)来完成。例如,控制反转(IoC)框架(如果您还没有听说过IoC,请查看MartinFowler的文章),或者一些负责用户配置的应用程序模块。
如果您使用的是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;
}
}
我的术语可能有点错误,但我认为您需要确定交互的组成根源;开始互动的是什么?
在我给出的Webforms示例中,Webform是由Http管道创建的,OnInit或OnLoad事件是管道中第一个可以"挂接"到进程的点(取决于您需要的上下文)。因此,您可以创建一个Presenter,并将您的Webform具体实例作为视图界面提供给它。
我不知道你正在讨论的Javascript框架,但我认为有一个初始化/调用步骤——在ASP.NET MVC中,这是ActionInvoker参与的时候,它是控制台应用程序中的Main。