ASP.NET WebForm MVP(一)- MVP模式简介
ASP.NET WebForm MVP(一)- MVP模式简介
基于这种框架的优点主要有:
事件模型。 Web 窗体支持与 Windows 应用程序类似的事件驱动编程模式。
状态管理。 Web 窗体通过使用视图状态和基于服务器的控件降低了状态管理的复杂性。
基于页面的体系结构。 Web 窗体提供了一种体系结构,此体系结构将含声明性标记的页面(.aspx 文件)与添加功能的代码隐藏文件相结合。 通过使用此结构,可以轻松地创建能够执行常规任务(如对用户操作作出响应以及呈现服务器代码中的标记)的页面。
大批控件。 ASP.NET 社区提供了数百个可减少开发时间的服务器控件和组件。
也正因为这些优点,能够很快的使用Web窗体框架开发应用程序。但基于Web窗体框架开发的应用程序是很难进行测试的,而且Web窗体框架中业务逻辑和页面显示逻辑混杂在一起,随着业务需求增加,应用程序变得愈加复杂,使得应用程序的质量难以保证,程序的维护也变得更加艰难。
于是发现可能使用MVP(Model-View-Presenter,模型-视图-表示器)模式的Web窗体框架能够在比较低的成本花费情况下提高我们的应用程序质量。
MVP模式的三层结构:
View(视图):显示应用程序的用户界面,根据用户操作激发相应的Presenter业务处理事件,并呈现处理后的视图状态
Presenter(表示器):响应View激发的处理事件,进行业务逻辑处理并将数据提交给Model层,最后根据操作结果更新视图状态
Model(业务模型):业务实体的持久化
由此可以看出通过这样的层次结构将UI的逻辑和业务实体的逻辑进行了清晰的分离,整体来说MVP模式主要有以下优点:
职责的分离。将职责分离到不同的部分后,使得复杂的业务能够简单的实现、使得应用程序的维护也变得更轻松,同时也能提高代码的重用性。
提高可测试性。以前的页面由于将不相关的部分(视图、业务模型、表示器)包含在一起,导致很难进行测试,但是将这些部分分离开来之后就使得测试变得容易。
多视图。将视图和业务模型分离之后,视图不会直接依赖于业务模型,那样我们能同时将相同的数据通过多个不同的视图进行展现。
适应变化。通常来说界面的变化往往比业务逻辑的变化更加频繁,不同的用户可能喜欢不同的展现风格、或者使用不同的设备进行展现,当业务模型不再依赖视图之后,添加新类型的展现视图变得更加容易,而且不会影响到业务模型。
而且MVP模式只是一种编程模型,在.NET平台中可以用在ASP.NET Web Form应用程序、Windows Forms应用程序等,现在也有一些实现了MVP模式的框架提供使用,主要有Claymore、MVC# Framework、NMVP Framework、ASP.NET Web Forms Model-View-Presenter (MVP)等。
通过上面对MVP模式的介绍,的确可能有些情况下在Web窗体中使用MVP模式会比MVC模式更适合,但哪个框架会比较适用还是需要通过实践来验证,接下来会继续介绍MVP的使用以及在使用过程中的一些体会。
ASP.NET WebForm MVP(二)- MVP模式的应用
上一篇文章主要介绍了MVP模式的一些基本概念,那么接下来主要介绍下MVP模式的使用。前面文章中提到了几个MVP模式的应用框架,但这些框架考虑到易用性、功能全面性等,实现得比较复杂,不是很适合拿来介绍MVP的使用,因此这里通过自己简单实现的MVP模式来介绍MVP模式的使用。
在WebForm中使用MVP模式后的业务的实现序列图如下图所示:
首先将IView的实例(Page)与Presenter绑定,当用户激发页面事件后,页面激发IView中定义的事件,并通过事件参数传递相关信息提供给已绑定的Presenter;Presenter会根据绑定的事件的响应函数操作业务实体,并获取操作后的业务实体状态,然后根据业务实体信息更新页面的Model信息(注意页面的Model与图中的Model是不同的概念);最终页面展现更新后的页面Model信息给用户。
接下来以用户列表页面为例(主要有两个简单的功能:用户列表的显示、指定用户的删除)通过简单的示例代码来实现上面过程。
首先定义IView接口IUserListView,主要包括了页面Model,以及加载用户列表事件和删除指定用户事件:
public interface IUserListView
{
UserListModel Model
{
get;
set;
}
event EventHandler LoadList;
event EventHandler<DeleteUserEventArgs> DeleteUser;
}
然后定义能够与IUserListView实例进行绑定的UserListPresenter,并添加IUserListView中定义的事件的响应函数:
public class UserListPresenter
{
private IUserListView _view;
public UserListPresenter(IUserListView view)
{
_view = view;
_view.Model = new UserListModel();
_view.LoadList += new EventHandler(LoadList);
_view.DeleteUser += new EventHandler<DeleteUserEventArgs>(DeleteUser);
}
public void LoadList(object sender, EventArgs args)
{
_view.Model.List = FakeData.UserList;
}
public void DeleteUser(object sender, DeleteUserEventArgs args)
{
User user = FakeData.UserList.First(u => u.ID == args.ID);
FakeData.UserList.Remove(user);
_view.Model.List = FakeData.UserList;
}
}
然后定义UserList页面,页面对象类除了以往的继承Page对象外,还需添加IUserListView接口以及接口的实现,然后在PageLoad事件中初始化Presenter的绑定,当需要获取或者操作业务实体时,只需要激发IUserListView中定义的相应事件(绑定的Presenter会响应该事件并更新页面Model),然后呈现页面Model中的数据:
protected void Page_Load(object sender, EventArgs e)
{
//使用当前IUserListView实例创建Presenter
_presenter = new UserListPresenter(this);
if (!IsPostBack)
{
LoadList(sender, e);
UserListBind();
}
}
protected void gvUserList_RowCommand(object sender, GridViewCommandEventArgs e)
{
int id = int.Parse(e.CommandArgument.ToString());
DeleteUser(sender, new DeleteUserEventArgs() { ID = id });
UserListBind();
}
以上基本就是MVP模式在WebForm中简单的应用,但如果是实际应用的话这些还是不够的,还有很多地方需要改进。
从上面看来使用MVP模式是不错的选择:
MVP模式的过程和原理都比较简单,只是在原有基础上增加了IView以及Presenter。
保留了原有的WebForm事件驱动方式的编程,团队学习成本低
由于对业务实体的操作已经被隔离到了Presenter,因此理论上是很容易进行单元测试的
但通过一年左右使用MVP模式进行WebForm的开发,发现在WebForm中使用MVP模式进行开发没上面看上去那么美好,下一篇文章将会总结MVP模式在使用过程中的一些体会。