根据Martin Fowler对MVP的描述(http://martinfowler.com/eaaDev/uiArchs.html)
在MVC的View部分中,Fowler说:
Potel的第一个元素是将视图视为窗口小部件的结构,这些窗口小部件与Forms and Controls模型的控件相对应,并删除任何视图/控件分离。MVP的视图是这些小部件的结构。它不包含任何描述小部件如何对用户交互做出反应的行为。
(加粗强调我的)
然后,演示者:
对用户行为的积极反应生活在单独的演示者对象中。小部件中仍然存在用户手势的基本处理程序,但是这些处理程序仅将控制权传递给presenter。
然后,演示者决定如何对事件做出反应。Potel主要根据模型上的动作来讨论这种交互,它是通过命令和选择系统来完成的。这里要强调的一个有用的事情是将所有编辑内容打包到命令中的方法-这为提供撤消/重做行为提供了良好的基础。
(再次,加粗强调我的)
因此,按照Fowler的指南,您的View不应对响应按钮事件的任何行为负责;其中包括创建的实例UserInfo
。决定创建对象的责任属于将UI事件转发到的Presenter方法。
但是,也可能会争辩说View的按钮事件处理程序也不应该负责传递两者的内容textView
,因为View应该只是将按钮事件转发到Presenter中,而仅此而已。
使用MVP,视图通常会实现一个接口,演示者可以使用该接口直接从视图中拾取数据(同时确保演示者仍然对视图本身不了解)。由于UserInfo是简单的POJO,因此对于视图公开UserInfo 的getter可能是有效的,Presenter可以通过接口从该Viewer拾取它。
// The view would implement IView
public interface IView {
public UserInfo GetUserInfo();
}
// Presenter
public class AddUserPresenter {
private IView addUserView;
public void SetView(IView view) {
addUserView = view
}
public void onSomethingClicked() {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
这UserInfo
与使用事件处理程序将直接传递到视图有何不同?主要区别在于,演示者仍然最终负责导致创建对象的逻辑UserInfo
。也就是说,事件在创建之前已到达Presenter UserInfo
,从而使Presenter可以做出决定。
设想一个场景,您有演示者逻辑,您不想UserInfo
基于视图中的某些状态创建演示者逻辑。例如,如果用户没有在视图上打勾,或者您对要添加到UserInfo中的某个字段进行了验证检查,但失败了-您的演示者可能在调用之前包含其他检查GetUserInfo
-即
private boolean IsUsernameValid() {
String username = addUserView.GetUsername();
return (username != null && !username.isEmpty());
}
public void onSomethingClicked() {
if (IsUsernameValid()) {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
该逻辑保留在演示者内部,无需将其添加到视图中。如果视图负责调用,GetUserInfo()
那么它也将负责与其使用有关的任何逻辑。这就是MVP模式要避免的事情。
因此,尽管创建方法实际上UserInfo
可能存在于View类中,但从视图类中永远不会调用它,而只能从Presenter中调用它。
当然,如果UserInfo
最终创建过程需要对用户输入窗口小部件的内容进行其他检查(例如,字符串转换,验证等),那么最好公开那些单独的吸气剂,以便进行验证/字符串转换放置在主持人内-然后主持人创建您的广告UserInfo
。
总体而言,关于Presenter / View之间的分离的主要目标是确保您永远不需要在视图中编写逻辑。如果您发现if
由于任何原因需要添加一条语句(即使它是if
有关小部件属性状态的一条语句-检查一个空的文本框或一个复选框的布尔值),那么它就属于演示者。
onSomethingClicked()
,因此,当用户单击“某物”时,View调用presenter.onSomethingClicked()
吗?或者在我的情况下,我的演示者方法应该命名为预期的操作addUser()
?