在某些项目中我们可能需要同时开发支持B/S和C/S模式的应用,在这样的背景下如何最大化的保证功能和代码通用性和适应性,就显得尤为重要了。在传统的B/S和C/S模式下,往往都是直接在页面UI类下直接进行控件的绑定、数据的验证和对业务逻辑的访问。这样的设计缺点是:依赖UI测试困难,控件代码和业务逻辑代码交织增加维护的难度。当业务需求变更时,需要转换或支持另一种客户端时都需要重新编写大量的页面逻辑。而采用Model-View-Presenter(MVP)可以保持各层功能的独立,使页面代码更加干净,测试更方便。
MVP简介
MVP是从经典的MVC模式演变而来,Model实现业务逻辑,Presenter实现程序逻辑,将View和Model完全分离,View实现页面接口。如下图:
从MVP模型图上我们可以了解到:
1 仅有Presenter能访问Model进行数据检索执行业务逻辑。
2 View依赖Presenter,包含Presenter实体。
3.Presenter不依赖具体的View实体,只包含View的接口(Presenter到View间的连线非直接连接)。
4.View不能访问Model.
为了说明使用MVP可以实现B/S和C/S模式下功能的通用,准备了一个小的实例来说明。要实现的功能就类似博客文章的分类的管理,可以浏览所有的分类添加删除分类。这个功能同时在asp.net和Windows Form中实现。
Model (业务逻辑)
实现的业务逻辑:查询、添加、删除分类。类图如下:
View接口
View接口是MVP模式中代码量最少的地方,但是如果要想快速看一个页面实现的功能就看View接口提供的对象。
本实例中ICategoryView成员如下类图:
1.AddedCategory:获取要输入的添加的分类;
2.Categories :显示要所有的分类;
3.DeletedCategory:获取输入的要删除的分类;
4.IsFirstLoaded :获取页面是否是第一显示,如果是第一次加载的话就显示出现有的所有分类。
5.StatusMessage :显示当前的操作处理状态。
Presenter
CatePresenter包括一个ICategoryView对象,类图如下:
Presenter仅包括View的接口,这样就可以测试时不需依赖具体的窗口或页面。
CategoryPresenter实现呈现层的逻辑,包括简单的输入检查,输入反馈,View控制和访问Model业务逻辑。
CategoryPresenter的具体实现:
{
private ICategoryView _View;
public CategoryPresenter(ICategoryView view)
{
_View = view;
}
public void OnCategorySave()
{
if (string.IsNullOrEmpty(_View.AddedCategory))
{
this._View.StatusMessage = "分类名不能为空";
return;
}
if (PostsLogic.ExistCategory(this._View.AddedCategory))
{
_View.StatusMessage = "分类名已存在!";
return;
}
PostsLogic.AddCategory(_View.AddedCategory);
this._View.Categories = PostsLogic.GetCategories();
}
public void OnViewLoaded()
{
if (this._View.IsFirstLoaded)
{
_View.Categories = PostsLogic.GetCategories();
}
}
public void OnCategoryDelete()
{
if (string.IsNullOrEmpty(_View.DeletedCategory))
{
this._View.StatusMessage = "请选择要删除的分类名";
return;
}
if (!PostsLogic.ExistCategory(_View.DeletedCategory))
{
this._View.StatusMessage = _View.DeletedCategory + ",分类名不存在!";
return;
}
PostsLogic.RemoveCategory(_View.DeletedCategory);
this._View.StatusMessage = "删除成功!";
this._View.Categories = PostsLogic.GetCategories();
}
}
CategoryPresenter初始化:
Windows Form中:
{
CategoryPresenter _Presenter;
public FrmCategory()
{
InitializeComponent();
_Presenter = new CategoryPresenter(this);
}
}
.aspx页面中:
{
private CategoryPresenter prsenter;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
prsenter = new CategoryPresenter(this);
}
}