最近在关注MVP模式的文章,看了张子阳的 MVP 模式实例解析和李春雷的MVP模式最佳实践(1)—MVP模式简介 ,自己也想弄一个来试试。
关于MVP模式的概念,网上很多,在此摘抄一段吧。
MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。Alex在他的blog中对于这两者之间的比较很直观也比较清楚,原文可以下面的地址找到:http://ameleta.spaces.live.com/blog/cns!5F6316345A821420!163.entry
准确的说,MVP模式和三层架构相比,MVP模式的编码量比较大,我个人认为普通的项目如果不涉及到WinFrom 与WebFrom 之间的转换,最好不要用MVP的模式。
下面我就以我所理解的MVP模式写一个小实例,是关于某个员工基本信息的数据绑定与编辑的操作。
在员工基本信息的编辑界面中,需要展示的信息包括员工的工号,姓名,性别,籍贯,出生年月等等,在此实例中我只展示这五个字段,一个绑定员工信息的方法,以及一个更新员工信息的事件。
首先,定义员工的Model层,该层代码与三层架构的实体层是相同的。
1namespace Model
2{
3 using System;
4 public class StaffInfo
5 {
6 private string _stfId;
7 private string _stfName;
8 private string _sex;
9 private string _native;
10 private string _birthDay;
11
12 public StaffInfo()
13 {
14 }
15
16 public StaffInfo(string stfId, string stfName, string sex, string native, string birthDay)
17 {
18 this._stfId = stfId;
19 this._stfName = stfName;
20 this._sex = sex;
21 this._native = native;
22 this._birthDay = birthDay;
23 }
24 /// <summary>
25 /// 员工工号
26 /// </summary>
27 public string StfId
28 {
29 get { return _stfId; }
30 set { _stfId = value; }
31 }
32 /// <summary>
33 /// 员工姓名
34 /// </summary>
35 public string StfName
36 {
37 get { return _stfName; }
38 set { _stfName = value; }
39 }
40 /// <summary>
41 /// 性别
42 /// </summary>
43 public string Sex
44 {
45 get { return _sex; }
46 set { _sex = value; }
47 }
48 /// <summary>
49 /// 籍贯
50 /// </summary>
51 public string Native
52 {
53 get { return _native; }
54 set { _native = value; }
55 }
56 /// <summary>
57 /// 出生年月
58 /// </summary>
59 public string BirthDay
60 {
61 get { return _birthDay; }
62 set { _birthDay = value; }
63 }
64 }
65}
第二步,定义员工的页面接口 IStaffDetailView ,在页面中,一般有一些常用的自定义函数,这时我们可以把它定义在父接口,然后用一个页面父类去实现它,如下面的MessageBox这个函数,就可以用这样的方式。那么我们页面接口就可以继承这个父接口,这样可以增强代码的重用性。
1namespace Presenter
2{
3 using System;
4 using Model;
5 public interface IStaffDetailView
6 {
7 /// <summary>
8 /// 员工工号
9 /// </summary>
10 string StfId { get;}
11
12 /// <summary>
13 /// 员工姓名
14 /// </summary>
15 string StfName { get;}
16
17 /// <summary>
18 /// 性别
19 /// </summary>
20 string Sex { get;}
21
22 /// <summary>
23 /// 籍贯
24 /// </summary>
25 string Native { get;}
26
27 /// <summary>
28 /// 出生年月
29 /// </summary>
30 string BirthDay { get;}
31
32 /// <summary>
33 /// 绑定员工信息
34 /// </summary>
35 /// <param name="infos"></param>
36 void BindDetail(StaffInfo> infos);
37
38 /// <summary>
39 /// 更新员工信息事件
40 /// </summary>
41 event EventHandler<EventArgs> UpdateEvent;
42 }
43}
第三步,定义员工数据访问类,我这里只是给一个示例,真实的项目中当然要封装一下才行。
第四步,定义员工Presenter层
1public class StaffDetailPresenter
2 {
3 private IStaffDetailView _view;
4
5 public StaffDetailPresenter(IStaffDetailView view)
6 {
7 this._view = view;
8 }
9
10 /// <summary>
11 /// 初始化页面
12 /// </summary>
13 /// <param name="IsPostBack">首次提交,WebFrom中,此值为IsPostBack,WinFrom中,此值为false</param>
14 public void InitializeView(bool IsPostBack)
15 {
16 if(!IsPostBack)
17 BindDetail();
18 this._view.UpdateEvent += new EventHandler<EventArgs>(View_UpdateEvent);
19 }
20
21 private void BindDetail()
22 {
23 this._view.BindDetail(new Staff(this._view.StfId));
24 }
25
26 private void View_UpdateEvent(object sender, EventArgs e)
27 {
28 if (new Staff().UpdateStaff(new Staff(this._view.StfId, this._view.StfName, this._view.Sex, this._view.Native, this._view.BirthDay)))
29 {
30 this.BindDetail();
31 this._view.MessageBox("更新成功");
32 }
33 else
34 this._view.MessageBox("更新失败!");
35 }
36 }
第五步:实现View接口,我这里以WebFrom为例,在页面中做了数据绑定与更新数据事件两个操作,还有如绑定GridView等等操作,大家可以探讨。
1namespace Web
2{
3 using System;
4 using System.Data;
5 using System.Data.SqlClient;
6 using System.Configuration;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Web;
10 using System.Web.Security;
11 using System.Web.UI;
12 using System.Web.UI.WebControls;
13 using System.Web.UI.WebControls.WebParts;
14 using System.Web.UI.HtmlControls;
15 using Presenter;
16 using Model;
17
18 public partial class StaffDetail : Page, IStaffDetailView
19 {
20 #region 实现接口
21 /// <summary>
22 /// 员工工号
23 /// </summary>
24 public string StfId { get { if (object.Equals(Request.QueryString["stfId"], null)) return null; return Request.QueryString["stfId"].ToString(); } }
25
26 /// <summary>
27 /// 员工姓名
28 /// </summary>
29 public string StfName { get { return txtStfName.Text; } }
30
31 /// <summary>
32 /// 性别
33 /// </summary>
34 public string Sex { get { return ddlSex.SelectValue; } }
35
36 /// <summary>
37 /// 籍贯
38 /// </summary>
39 public string Native { get { return txtNative.Text; } }
40
41 /// <summary>
42 /// 出生年月
43 /// </summary>
44 public string BirthDay { get { return txtBirthDay.Text; } }
45
46 /// <summary>
47 /// 绑定员工信息
48 /// </summary>
49 /// <param name="info"></param>
50 public void BindDetail(StaffInfo info)
51 {
52 lbStfId.Text = info.StfId;
53 txtStfName.Text = info.StfName;
54 ddlSex.SelectValue = info.Sex;
55 txtNative.Text = info.Native;
56 txtBirthDay.Text = info.BirthDay;
57 }
58
59 /// <summary>
60 /// 弹出对话框
61 /// </summary>
62 /// <param name="msg">对话框消息</param>
63 public void MessageBox(string msg)
64 {
65 string script = string.Format("<script language='javascript' type='text/javascript' defer>window.alert('{0}');</script>", msg);
66 this.ClientScript.RegisterStartupScript(this.GetType(), "系统提示", script);
67 }
68
69 /// <summary>
70 /// 更新员工信息事件
71 /// </summary>
72 public event EventHandler<EventArgs> UpdateEvent;
73 #endregion
74
75 protected void Page_Load(object sender, EventArgs e)
76 {
77 StaffDetailPresenter p = new StaffDetailPresenter(this);
78 p.InitializeView(IsPostBack);
79 }
80
81 protected void btn_Update(object sender, EventArgs e)
82 {
83 if (this.UpdateEvent != null)
84 this.UpdateEvent(sender, e);
85 }
86 }
87
88}
以上是整个实例的代码。这个实例与李春雷的实例的大体结构类似,不同之处在于以下两点
1、视图接口中增加了按钮事件,这个思路来源于http://www.cnblogs.com/chinasf/archive/2006/12/20/597987.html;
2、明确了Model层与Control层的职责,在Model层的设计中我采用了与三层框架的实体层相同的方式,DataAccess作为Control层,它的作用在于对数据库进行操作。
欢迎大家来批评指正。
转自:http://www.cnblogs.com/easyit/archive/2009/05/12/1454786.html