Model-View-Presenter 中的 Presenter 是否创建视图?
MVP 中的视图是如何创建的? Presenter 是否总是创建它们(除了子视图的 View 之外)?或者它是一个单独的第三方组件或应用程序或创建它们的东西?
我们还要补充一点,我可能会在 Dojo Toolkit/ExtJS(即 JavaScript)上执行此操作。
所以,我有这些代码行:
var v = new MyApp.view.User();
var p = new MyApp.presenter.User();
这两行代码到底应该放在哪里?演示者是否实例化视图,或者反之亦然?第一个实例是由什么实例化的?
How are Views created in MVP? Does the Presenter always create them (in addition to View in case of subviews)? Or is it a separate third-party component or App or something that creates them?
Let's also add that I'm probably going to do this on Dojo Toolkit/ExtJS (JavaScript that is).
So, I have these code lines:
var v = new MyApp.view.User();
var p = new MyApp.presenter.User();
where should both lines go exactly? Does the presenter instantiate the view, or vice-versa? And what instantiates the first instance?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这取决于...
MVP 的主要目标是将复杂的决策逻辑与 UI 代码分开,使两者变得更易于理解和维护。通常另一个目标是使演示器中的决策逻辑可测试。
Fowler 在 2004 年描述了 MVP 模式,他在 2006 年停用了该模式,将该模式拆分为 < a href="http://martinfowler.com/eaaDev/SupervisingPresenter.html" rel="noreferrer">监督控制器 (SC) 和 被动视图 (PV)。在SC中,View与Model绑定,但在PV中则不然;在PV中,View只能由Presenter直接改变。
在 SC 和 PV 中,演示者必须更新视图并对用户对视图所做的更改做出反应,例如输入文本或按下按钮。当您让 View 调用 Presenter 上的方法时,就会出现您所描述的问题,因为 View 需要对 Presenter 的引用,反之亦然。如果您这样做,您只需决定谁来启动这一切。选项有:
所有选项都允许您实现关注点分离和提高决策逻辑的可测试性的“MVP 目标”。我不认为这些方法在理论上是正确或错误的——您只需选择最适合您使用的技术的方法即可。最好在整个申请过程中保持一致的选择。
It depends ...
The main goal of MVP is to separate complex decision logic from UI code in such a way that both become easier to understand and to maintain. Often another goal is to make the decision logic in the presenter testable.
The MVP pattern was described by Fowler in 2004 and he retired it in 2006 by splitting the pattern into Supervising Conroller (SC) and Passive View (PV). In SC, the View is bound to the Model but not in PV; in PV, the View is only changed by the Presenter directly.
In both SC and PV, the Presenter has to update the View and react to changes the user made to the View, such as entering text or pressing a button. When you let the View call methods on the Presenter, then the problem you describe arises because the View needs a reference to the Presenter and vice versa. If you do this, you simply can make a decision who starts it all up. Options are:
All options allow you to reach "MVP goals" of separation of concerns and increased testability of decision logic. I don't think any of these methods is theoretically right or wrong –you just have to pick the one that is most appropriate to the technology you use. And it's best to be consistent in your choice throughout the application.
您可以选择以下选项:
ContactViewPresenter
构造函数设置this.view = viewParam
,并设置this.view.presenter = this
。它将代码保留在 Presenter 中,必要时可以交换视图,并且可以传入视图的模拟来进行测试。
ContactView
构造函数设置this.presenter = cvpParam
和this.presenter.view = this
。View 中有一些逻辑,但不是很多。如有必要,可以更换演示者。
这是更多的代码。
构造函数创建集合
this.view = new ContactView()
和this.view.presenter = this
。构造函数设置
this.presenter = new ContactViewPresenter()
和this.presenter.view = this
最后两个似乎有点过于耦合。
其一是代码保留在 Presenter 中,并且似乎可以更轻松地进行测试。
两个很好,因为您不必太关心演示者,而可以更多地担心您的视图。
These are your options:
ContactViewPresenter
constructor setsthis.view = viewParam
, and setsthis.view.presenter = this
.It keeps the code in the Presenter, it can swap out views if necessary, and it could pass in a mock of the view for testing.
ContactView
constructor setsthis.presenter = cvpParam
, andthis.presenter.view = this
.Some logic in View, but not a lot. Can swap out presenter if necessary.
This is a lot more code.
Constructor creates sets
this.view = new ContactView()
andthis.view.presenter = this
.Constructor sets
this.presenter = new ContactViewPresenter()
andthis.presenter.view = this
The last two seem a bit too coupled.
One is nice in that the code stays in the Presenter, and seems to allow for easier testing.
Two is nice in that you don't have to care about the Presenters too much and can worry about your Views more.
我认为 Presenter 不应该实例化视图,这应该由 MVP 三元组之外的实体(不是面向数据的意义上,我的意思是一般实体)来完成。例如,控制反转 (IoC) 框架(如果您还没有听说过 IoC,请查看 Martin Fowler 的文章),或者一些负责用户配置的应用程序模块。
I don't think the Presenter should instantiate the view, that should be done by an entity (not in the data-oriented sense, I mean a general entity) outside of the MVP triad. For example, an Inversion of Control (IoC) framework (if you haven't heard about IoC, check Martin Fowler's article), or some application module responsible for user configuration.
如果您使用的是 WebForms,那么 WebForm OnLoad 或 Init 应该是您创建 Presenter 的位置 - 然后将接口引用传递给 WebForm 实现的 View。
所以,像这样:
Presenter 构造函数的定义如下:
If you are using WebForms then the WebForm OnLoad or Init should be the place where you create the Presenter - this is then passed an interface reference to the View which the WebForm implements.
So, something like this:
And the Presenter constructor is defined thus:
我的术语可能略有错误,但我认为你需要确定交互的构成根源;开始交互的是什么?
在我给出的 Webforms 示例中,Webform 是由 Http 管道创建的,OnInit 或 OnLoad 事件是管道中的第一个点(取决于您需要的上下文),您可以“挂钩”到该流程。因此,您创建一个 Presenter 并为其提供 Webform 的具体实例作为视图界面。
我不知道您正在讨论的 Javascript 框架,但我认为有一个初始化/调用步骤 - 在 ASP.NET MVC 中,这是 ActionInvoker 参与的时候,它是控制台应用程序中的 Main。
I may have the terminology slightly wrong but I think you need to identify the composition root of your interaction; what is the thing that begins the interaction?
In the Webforms example I gave, the Webform is created by the Http pipeline, the OnInit or OnLoad event is the first point in the pipeline ( depending on what context you need ) that you can 'hook in' to the process. Thus, you create a Presenter and give it your concrete instance of a Webform as a View Interface.
I don't know the Javascript frameworks you are discussing but I presume there is an initialisation / invocation step - in ASP.NET MVC this is when an ActionInvoker gets involved, it's the Main in a Console App.