初看MVP模式时被它复杂的包含,继承,接口搞晕,View中有Presenter,Presenter中又有View,View又要抽象出IView,View又调用Presenter的方法,Presenter又调用IView的方法.花了点时间算是搞明白了,这里说说自己的理解.
关于MVP模式文章一搜一大把.建议先看看这些文章.
Artceh
http://www.cnblogs.com/artech/archive/2010/04/12/1710681.html
http://www.cnblogs.com/artech/archive/2010/03/25/1696205.html
Jianqiang Bao
http://www.cnblogs.com/jax/archive/2009/10/09/1579404.html
Microsoft
http://www.microsoft.com/china/msdn/library/architecture/architecture/architecturetopic/MVP.mspx?mfr=true
理解MVP模式,其实很简单
借用
Artceh的图片
可以把V和P的交互想象成一个HTTTP请求,View为客户端,Presenter相当于服务器端,处理流程:
1.View发生一些事件,一般就是页面事件,按钮点击事件等.
2.View请求Presenter处理.
3.Presenter整合调度Model的方法处理.
4.Presenter调用View的方法作为回应.
流程就这么简单,搞明白这个基本就差不多了.
开发MVP模式的一般流程
结合实例总结一下用MVP开发的步骤.例子很简单,就是显示一个List.可以显示全部员工,也可以显示属于某个项目的员工.
1.抽象出IView.根据页面功能抽象.可分为两个部分.
请求部分,对应Winform,Webform的各种页面,控件事件,参考Artceh的文章,请求部分应该是自定义事件.在这个例子中,没有按钮点击,也没有下拉框改变,只有页面的load事件,所以请求部分就是一个ViewLoad.
响应部分,是提供给Presenter操作View的,例如显示数据,显示错误提示,清空控件状态等.在这个例子中当然就是把一些数组show出来,考虑到将来有可能有多个控件的数据绑定,所以把数据绑定放在一个方法中,直接this.DataBind()就可以,不用每个控件都绑定一次,简单点的话不要这个PageDataBind也可以.
为了更清晰,我用partial 类,接口把每个关注点分开了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
namespace
WebAppMVP.IView
{
/// <summary>
/// 请求部分,对应各种事件,页面事件,按钮单击事件,下拉框改变事件等等
/// 要在View中封装处理一下,不能直接把对应的事件丢给Presenter
/// 所以下面的事件参数为,ListEmployeeEventArgs
/// </summary>
public
partial interface
IListEmployeeView
{
event
EventHandler<ListEmployeeEventArgs> ViewLoad;
}
/// <summary>
/// 回应部分
/// </summary>
public
partial interface
IListEmployeeView
{
void
ShowEmployee(ListEmployeeViewModel vm);
void
PageDataBind();
}
}
|
2自定义请求参数.
请求部分是一个自定义事件,所以ListEmployeeEventArgs是这个事件的自定义参数,通过封装这些参数,就可以把与业务无关的代码过滤掉.在这个页面功能中,因为需要显示属于某个项目的员工,所以参数当然就是ProjectId(Name是多余的,我不想再查询一次,其实只需ProjectId即可).
1
2
3
4
5
6
7
8
9
|
namespace
WebAppMVP.IView.EventArgs
{
public
class ListEmployeeEventArgs : System.EventArgs
{
public
int ? ProjectId {
get ; set ; }
public
string Name {
get ; set ; }
}
}
|
3.同理,一个用作显示的参数也是必要的.
1
2
3
4
5
6
7
8
9
10
|
namespace
WebAppMVP.ViewModel
{
public
class ListEmployeeViewModel
{
public
string ProjectName {
get ;
set ; }
public
Employee[] Employees { get ;
set ; }
}
}
|
4.Presenter.
在Presenter中用构造函数注入一个IView.
订阅IView的事件.
事件处理方法中包含两个部分,1根据参数处理业务,2调用IView定义的方法作为回应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
namespace
WebAppMVP.Presenter
{
public
partial class
ListEmployeePresenter
{
IListEmployeeView m_IView {
get ;
set ; }
MockData mockData =
new MockData();
public
ListEmployeePresenter(IListEmployeeView iview)
{
this .m_IView = iview;
this .m_IView.ViewLoad += (sender, args) =>
{
#region 业务逻辑
ListEmployeeViewModel vm =
new ListEmployeeViewModel();
if
(args.ProjectId.HasValue)
{
vm.ProjectName = args.Name;
vm.Employees = mockData.Employees.Where(e => e.Projects.Any(p => p.Id == args.ProjectId.Value)).Take(10).ToArray();
}
else
{
vm.ProjectName =
string .Empty;
vm.Employees = mockData.Employees.Take(10).ToArray();
}
#endregion
#region 显示数据,作为回应
this .m_IView.ShowEmployee(vm);
this .m_IView.PageDataBind();
#endregion
};
}
}
}
|
5.View.
这里我也分为三个部分.
初始化部分在View中继承IView,实例化一个Presenter.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/// <summary>
/// 初始化部分,每个页面基本雷同
/// </summary>
public
partial class
ListEmployeeView : System.Web.UI.Page, IListEmployeeView
{
public
event EventHandler<ListEmployeeEventArgs> ViewLoad;
private
ListEmployeePresenter m_Presenter;
protected
void Page_Init( object
sender, EventArgs e)
{
m_Presenter =
new ListEmployeePresenter( this );
}
}
|
请求部分在对应的页面,控件事件中准备XXXEventArgs参数,触发方法IView的自定义事件.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/// <summary>
/// 请求部分,这里的职责就是监视页面发生什么事件,出现什么状况,准备对应的参数,请求Presenter处理它
/// </summary>
public
partial class
ListEmployeeView
{
protected
void Page_Load( object
sender, EventArgs e)
{
#region 准备数据,参数,UI逻辑,实现了将这些UI相关代码与真正业务逻辑隔离
ListEmployeeEventArgs args =
new ListEmployeeEventArgs();
if
(Request.QueryString.AllKeys.Contains( "id" ))
{
var id = 0;
if
( int .TryParse(Request.QueryString[ "id" ],
out id))
{
args.ProjectId = id;
args.Name = HttpUtility.UrlDecode(Request.QueryString[ "name" ]);
}
else
{
args.ProjectId =
null ;
args.Name =
string .Empty;
}
}
else
{
args.ProjectId =
null ;
args.Name =
string .Empty;
}
#endregion
ViewLoad(sender, args);
}
}
|
响应部分,实现IView中定义的响应方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
namespace
WebAppMVP.View
{
/// <summary>
/// 响应部分,这里对应的方法的职责非常简单--显示数据,信息等等,这里不知道Presenter,没有业务逻辑.
/// </summary>
public
partial class
ListEmployeeView
{
public
void ShowEmployee(ListEmployeeViewModel vm)
{
this .rpEmployee.DataSource = vm.Employees;
this .Title =
string .IsNullOrEmpty(vm.ProjectName) ?
"员工列表" : vm.ProjectName +
"的员工列表" ;
this .lbProjectName.Text =
this .Title;
}
public
void PageDataBind()
{
this .DataBind();
}
}
}
|
简单总结
1.首先发现是,有很多XXX.cs,也就是说类文件和类,接口会多好几倍.
2.功能,职责很清晰,可测试性也大大提高.
3.跟传统开发差别较大,相对有点不好理解,相信这也是很少人用的原因
4.疑问1,没有用来做过实际项目,不知道应对需求变更方面能力如何?
5.疑问2,可以看到上面基本没有提到M,基本是PV的交互,感觉MVP中的M作用相对较弱,是一个类似Domain Service的角色,小一点的系统中M完全可以不要(不过小系统也没必要用MVP了).
the end
相关推荐
Retrofit+MVP模式 最最简单的案例 若有错误请指出
android mvp设计模式demo。官方源码实现mvp模式,结构清晰,一目了然。
MVP模式计算器事例,网络上找到的资源,MVP模式开发,web,winform切换非常容易。
该项目快捷简洁的实现了Android mvp模式,非常明了易懂
很简单的一款mvp模式,简单易懂,适合初学者所学
说说Android的MVP模式1
源代码解析MVP模式 很好的学习资料,推荐!
MVP模式安卓开发案例
一个MVP的Demo,展示了在iOS平台上如何实现MVP模式 希望通过这个项目能让大家了解如何在iOS平台上实现MVP模式
android MVP模式例子源码,封装了一个对数据库操作的类,实现了对数据的进行数据库的存取,具体MVP模式教程参考博客http://blog.csdn.net/u012925323/article/details/50409422,希望对大家有帮助。
android MVP模式的简单练习,可以由此比较好的理解这个模式。
一个简单的android mvp模式,帮助新手理解mvp模式。简单的登录。
MVP模式
使用mvp模式实现的用户登录和注册功能
MVP demo
MVP模式的选择 多选
android mvp模式简单工程,用于理解mvp模式
Android Mvp模式 Demo