MVP模式及实例
最近在关注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层,该层代码与三层架构的实体层是相同的。
1
namespace Model2


{3
using System;4
public class StaffInfo5

{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 StfId28

{29

get
{ return _stfId; }30

set
{ _stfId = value; }31
}32

/**//// <summary>33
/// 员工姓名34
/// </summary>35
public string StfName36

{37

get
{ return _stfName; }38

set
{ _stfName = value; }39
}40

/**//// <summary>41
/// 性别42
/// </summary>43
public string Sex44

{45

get
{ return _sex; }46

set
{ _sex = value; }47
}48

/**//// <summary>49
/// 籍贯50
/// </summary>51
public string Native52

{53

get
{ return _native; }54

set
{ _native = value; }55
}56

/**//// <summary>57
/// 出生年月58
/// </summary>59
public string BirthDay60

{61

get
{ return _birthDay; }62

set
{ _birthDay = value; }63
}64
}65
}
第二步,定义员工的页面接口 IStaffDetailView ,在页面中,一般有一些常用的自定义函数,这时我们可以把它定义在父接口,然后用一个页面父类去实现它,如下面的MessageBox这个函数,就可以用这样的方式。那么我们页面接口就可以继承这个父接口,这样可以增强代码的重用性。
1
namespace Presenter2


{3
using System;4
using Model;5
public interface IStaffDetailView6

{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
}
第三步,定义员工数据访问类,我这里只是给一个示例,真实的项目中当然要封装一下才行。
1
namespace DataAccess2


{3
using System;4
using System.Data;5
using System.Data.SqlClient;6
using Model;7

8
public class Staff9

{10
private static string connectionString = "server=.;database=db;user id=sa;password=password";11

12

/**//// <summary>13
/// 获取员工信息14
/// </summary>15
/// <param name="stfId">员工工号</param>16
/// <returns></returns>17
private StaffInfo GetStaffDetail(string stfId)18

{19
string cmdText = "select stfName,sex,native,birthDay from tb_Staff where stfId=@stfId";20
SqlConnection con = new SqlConnection(connectionString);21
SqlDataAdapter da = new SqlDataAdapter(cmdText,con);22
DataTable dt = new DataTable();23
da.SelectCommand.CommandType = CommandType.Text;24
SqlParameter[] paras = new SqlParameter[]25

{26
new SqlParameter("@stfId",SqlDbType.VarChar,10)27
};28

29
paras[0].Value = stfId;30

31
foreach (SqlParameter para in paras)32

{33
da.SelectCommand.Parameters.Add(para);34
}35
try36

{37
con.Open();38
da.Fill(dt);39
con.Close();40
StaffInfo info = new StaffInfo();41
foreach (DataRow dr in dt.Rows)42

{43
info.StfName = dr[0].ToString();44
info.Sex = dr[1].ToString();45
info.Native = dr[2].ToString();46
info.BirthDay = dr[3].ToString();47
}48
return info;49
}50
catch (Exception ex)51

{52
throw new Exception(ex.Message);53
}54
}55

56

/**//// <summary>57
/// 更新员工信息58
/// </summary>59
/// <param name="info"></param>60
/// <returns></returns>61
private bool UpdateStaff(StaffInfo info)62

{63
string cmdText = "update tb_Staff set stfName=@stfName,sex=@sex,native=@native,birthDay=@birthDay where stfId=@stfId";64
SqlConnection con = new SqlConnection(connectionString);65
SqlCommand cmd = new SqlCommand(cmdText, con);66
SqlParameter[] paras = new SqlParameter[]67

{68
new SqlParameter("@stfId",SqlDbType.VarChar,10),69
new SqlParameter("@stfName",SqlDbType.NVarChar,20),70
new SqlParameter("@sex",SqlDbType.NVarChar,1),71
new SqlParameter("@native",SqlDbType.NVarChar,20),72
new SqlParameter("@birthDay",SqlDbType.VarChar,10)73
};74

75
paras[0].Value = info.StfId;76
paras[1].Value = info.StfName;77
paras[2].Value = info.Sex;78
paras[3].Value = info.Native;79
paras[4].Value = info.BirthDay;80

81
foreach (SqlParameter para in paras)82

{83
cmd.Parameters.Add(para);84
}85
try86

{87
con.Open();88
cmd.EndExecuteNonQuery();89
con.Close();90
return true;91
}92
catch 93

{94
return false;95
}96
}97
}98
}第四步,定义员工Presenter层
1
public class StaffDetailPresenter2

{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
else34
this._view.MessageBox("更新失败!");35
}36
}第五步:实现View接口,我这里以WebFrom为例,在页面中做了数据绑定与更新数据事件两个操作,还有如绑定GridView等等操作,大家可以探讨。
1
namespace Web2


{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, IStaffDetailView19

{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
#endregion74

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层,它的作用在于对数据库进行操作。
欢迎大家来批评指正。
浙公网安备 33010602011771号