最近公司在做一个医疗项目,使用WinForm界面作为客户端交互界面。在整个客户端解决方案中。使用了MVP模式实现。由于之前没有接触过该设计模式,所以在项目完成到某个阶段时,将使用MVP的体会写在博客里面。
所谓的MVP指的是Model,View,Presenter。对于一个UI模块来说,它的所有功能被分割为三个部分,分别通过Model、View和Presenter来承载。Model、View和Presenter相互协作,完成对最初数据的呈现和对用户操作的响应,它们具有各自的职责划分。Model可以看成是模块的业务逻辑和数据的提供者;View专门负责数据可视化的呈现,和用户交互事件的响应。一般地,View会实现一个相应的接口;Presenter是一般充当Model和View的纽带。
其依赖关系为:
View直接依赖Presenter,即在View实体保存了Presenter的引用; 而Presenter通过依赖View的接口,实现对View的数据推送和数据呈现任务的分配(Presenter处理完业务逻辑之后,在需要展示数据时,通过调用View的接口,将数据推送给View);Model与View之间不存在依赖关系,Model与Presenter之间存在依赖关系。
如下图所示:
MVP模式中有一个比较特殊的地方,就是虽然View有依赖Preserter,但是不应该由View主动的去访问Presenter,View职责:接收用户的的请求,将请求提交给Presenter,在适合的时候展示数据(Presenter处理完请求之后,会主动将数据推送)。如何设计,才能防止View主动访问Presenter呢?通过事件订阅的机制,View的接口中,将所有可能处理的请求做成事件,然后由Presenter去订阅该事件,那么客户端需要处理请求时,就直接调用事件。代码如下:
/// <summary> /// 窗体的抽象基类 /// </summary> public partial class BaseView : DockContent { protected ViewHelper viewHelper; public BaseView() { InitializeComponent(); //viewHelper负责动态的创建Presenter,并保存起来。 viewHelper = new ViewHelper(this); this.FormClosing += BaseView_FormClosing; } void BaseView_FormClosing(object sender, FormClosingEventArgs e) { if (hook != null) { hook.UnInstall(); } } #region 公共弹窗方法 public void ShowInformationMsg(string msg, string caption) { if (this.InvokeRequired) { this.Invoke(new Action(() => { MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Information); this.Focus(); })); } else { MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Information); this.Focus(); } } public void ShowErrorMsg(string msg, string caption) { if (this.InvokeRequired) { this.Invoke(new Action(() => { MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); this.Focus(); })); } else { MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); this.Focus(); } } public void ShowInformationList(List<string> msgList, string caption) { if (this.InvokeRequired) { this.Invoke(new Action(() => { Frm_TipMsg frmTip = new Frm_TipMsg(caption,msgList); frmTip.ShowDialog(); this.Focus(); })); } else { Frm_TipMsg frmTip = new Frm_TipMsg(caption, msgList); frmTip.ShowDialog(); this.Focus(); } } #endregion }