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层,该层代码与三层架构的实体层是相同的。

ContractedBlock.gif ExpandedBlockStart.gif Code
 1namespace Model
 2ExpandedBlockStart.gifContractedBlock.gif{
 3    using System;
 4    public class StaffInfo
 5ExpandedSubBlockStart.gifContractedSubBlock.gif    {
 6        private string _stfId;
 7        private string _stfName;
 8        private string _sex;
 9        private string _native;
10        private string _birthDay;
11
12        public StaffInfo()
13ExpandedSubBlockStart.gifContractedSubBlock.gif        {
14        }

15
16        public StaffInfo(string stfId, string stfName, string sex, string native, string birthDay)
17ExpandedSubBlockStart.gifContractedSubBlock.gif        {
18            this._stfId = stfId;
19            this._stfName = stfName;
20            this._sex = sex;
21            this._native = native;
22            this._birthDay = birthDay;
23        }

24ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
25        /// 员工工号
26        /// </summary>

27        public string StfId
28ExpandedSubBlockStart.gifContractedSubBlock.gif        {
29ExpandedSubBlockStart.gifContractedSubBlock.gif            get return _stfId; }
30ExpandedSubBlockStart.gifContractedSubBlock.gif            set { _stfId = value; }
31        }

32ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
33        /// 员工姓名
34        /// </summary>

35        public string StfName
36ExpandedSubBlockStart.gifContractedSubBlock.gif        {
37ExpandedSubBlockStart.gifContractedSubBlock.gif            get return _stfName; }
38ExpandedSubBlockStart.gifContractedSubBlock.gif            set { _stfName = value; }
39        }

40ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
41        /// 性别
42        /// </summary>

43        public string Sex
44ExpandedSubBlockStart.gifContractedSubBlock.gif        {
45ExpandedSubBlockStart.gifContractedSubBlock.gif            get return _sex; }
46ExpandedSubBlockStart.gifContractedSubBlock.gif            set { _sex = value; }
47        }

48ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
49        /// 籍贯
50        /// </summary>

51        public string Native
52ExpandedSubBlockStart.gifContractedSubBlock.gif        {
53ExpandedSubBlockStart.gifContractedSubBlock.gif            get return _native; }
54ExpandedSubBlockStart.gifContractedSubBlock.gif            set { _native = value; }
55        }

56ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
57        /// 出生年月
58        /// </summary>

59        public string BirthDay
60ExpandedSubBlockStart.gifContractedSubBlock.gif        {
61ExpandedSubBlockStart.gifContractedSubBlock.gif            get return _birthDay; }
62ExpandedSubBlockStart.gifContractedSubBlock.gif            set { _birthDay = value; }
63        }

64    }

65}

 

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

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1namespace Presenter
 2ExpandedBlockStart.gifContractedBlock.gif{
 3    using System;
 4    using Model;
 5    public interface IStaffDetailView
 6ExpandedSubBlockStart.gifContractedSubBlock.gif    {
 7ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 8        /// 员工工号
 9        /// </summary>

10ExpandedSubBlockStart.gifContractedSubBlock.gif        string StfId get;}
11
12ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
13        /// 员工姓名
14        /// </summary>

15ExpandedSubBlockStart.gifContractedSubBlock.gif        string StfName get;}
16
17ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
18        /// 性别
19        /// </summary>

20ExpandedSubBlockStart.gifContractedSubBlock.gif        string Sex get;}
21
22ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
23        /// 籍贯
24        /// </summary>

25ExpandedSubBlockStart.gifContractedSubBlock.gif        string Native get;}
26
27ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
28        /// 出生年月
29        /// </summary>

30ExpandedSubBlockStart.gifContractedSubBlock.gif        string BirthDay get;}
31
32ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
33        /// 绑定员工信息
34        /// </summary>
35        /// <param name="infos"></param>

36        void BindDetail(StaffInfo> infos);
37
38ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
39        /// 更新员工信息事件
40        /// </summary>

41        event EventHandler<EventArgs> UpdateEvent;
42    }

43}

 

第三步,定义员工数据访问类,我这里只是给一个示例,真实的项目中当然要封装一下才行。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1namespace DataAccess
 2ExpandedBlockStart.gifContractedBlock.gif{
 3    using System;
 4    using System.Data;
 5    using System.Data.SqlClient;
 6    using Model;
 7
 8    public class Staff
 9ExpandedSubBlockStart.gifContractedSubBlock.gif    {
10        private static string connectionString = "server=.;database=db;user id=sa;password=password";
11
12ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
13        /// 获取员工信息
14        /// </summary>
15        /// <param name="stfId">员工工号</param>
16        /// <returns></returns>

17        private StaffInfo GetStaffDetail(string stfId)
18ExpandedSubBlockStart.gifContractedSubBlock.gif        {
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[]
25ExpandedSubBlockStart.gifContractedSubBlock.gif            {
26               new SqlParameter("@stfId",SqlDbType.VarChar,10)
27            }
;
28
29            paras[0].Value = stfId;
30
31            foreach (SqlParameter para in paras)
32ExpandedSubBlockStart.gifContractedSubBlock.gif            {
33                da.SelectCommand.Parameters.Add(para);
34            }

35            try
36ExpandedSubBlockStart.gifContractedSubBlock.gif            {
37                con.Open();
38                da.Fill(dt);
39                con.Close();
40                StaffInfo info = new StaffInfo();
41                foreach (DataRow dr in dt.Rows)
42ExpandedSubBlockStart.gifContractedSubBlock.gif                {
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)
51ExpandedSubBlockStart.gifContractedSubBlock.gif            {
52                throw new Exception(ex.Message);
53            }

54        }

55
56ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
57        /// 更新员工信息
58        /// </summary>
59        /// <param name="info"></param>
60        /// <returns></returns>

61        private bool UpdateStaff(StaffInfo info)
62ExpandedSubBlockStart.gifContractedSubBlock.gif        {
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[]
67ExpandedSubBlockStart.gifContractedSubBlock.gif            {
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)
82ExpandedSubBlockStart.gifContractedSubBlock.gif            {
83                cmd.Parameters.Add(para);
84            }

85            try
86ExpandedSubBlockStart.gifContractedSubBlock.gif            {
87                con.Open();
88                cmd.EndExecuteNonQuery();
89                con.Close();
90                return true;
91            }

92            catch 
93ExpandedSubBlockStart.gifContractedSubBlock.gif            {
94                return false;
95            }

96        }

97    }

98}

第四步,定义员工Presenter层

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1public class StaffDetailPresenter
 2ExpandedBlockStart.gifContractedBlock.gif    {
 3        private IStaffDetailView _view;
 4
 5        public StaffDetailPresenter(IStaffDetailView view)
 6ExpandedSubBlockStart.gifContractedSubBlock.gif        {
 7            this._view = view;
 8        }

 9
10ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
11        /// 初始化页面
12        /// </summary>
13        /// <param name="IsPostBack">首次提交,WebFrom中,此值为IsPostBack,WinFrom中,此值为false</param>

14        public void InitializeView(bool IsPostBack)
15ExpandedSubBlockStart.gifContractedSubBlock.gif        {
16            if(!IsPostBack)
17                BindDetail();
18            this._view.UpdateEvent += new EventHandler<EventArgs>(View_UpdateEvent);
19        }

20
21        private void BindDetail()
22ExpandedSubBlockStart.gifContractedSubBlock.gif        {
23            this._view.BindDetail(new Staff(this._view.StfId));
24        }

25
26        private void View_UpdateEvent(object sender, EventArgs e)
27ExpandedSubBlockStart.gifContractedSubBlock.gif        {
28            if (new Staff().UpdateStaff(new Staff(this._view.StfId, this._view.StfName, this._view.Sex, this._view.Native, this._view.BirthDay)))
29ExpandedSubBlockStart.gifContractedSubBlock.gif            {
30                this.BindDetail();
31                this._view.MessageBox("更新成功");
32            }

33            else
34                this._view.MessageBox("更新失败!");
35        }

36    }

第五步:实现View接口,我这里以WebFrom为例,在页面中做了数据绑定与更新数据事件两个操作,还有如绑定GridView等等操作,大家可以探讨。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
 1namespace Web
 2ExpandedBlockStart.gifContractedBlock.gif{
 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
19ExpandedSubBlockStart.gifContractedSubBlock.gif    {
20ContractedSubBlock.gifExpandedSubBlockStart.gif        实现接口#region 实现接口
21ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
22        /// 员工工号
23        /// </summary>

24ExpandedSubBlockStart.gifContractedSubBlock.gif        public string StfId get if (object.Equals(Request.QueryString["stfId"], null)) return nullreturn Request.QueryString["stfId"].ToString(); } }
25
26ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
27        /// 员工姓名
28        /// </summary>

29ExpandedSubBlockStart.gifContractedSubBlock.gif        public string StfName get return txtStfName.Text; } }
30
31ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
32        /// 性别
33        /// </summary>

34ExpandedSubBlockStart.gifContractedSubBlock.gif        public string Sex get return ddlSex.SelectValue; } }
35
36ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
37        /// 籍贯
38        /// </summary>

39ExpandedSubBlockStart.gifContractedSubBlock.gif        public string Native get return txtNative.Text; } }
40
41ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
42        /// 出生年月
43        /// </summary>

44ExpandedSubBlockStart.gifContractedSubBlock.gif        public string BirthDay get return txtBirthDay.Text; } }
45
46ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
47        /// 绑定员工信息
48        /// </summary>
49        /// <param name="info"></param>

50        public void BindDetail(StaffInfo info)
51ExpandedSubBlockStart.gifContractedSubBlock.gif        {
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
59ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
60        /// 弹出对话框
61        /// </summary>
62        /// <param name="msg">对话框消息</param>

63        public void MessageBox(string msg)
64ExpandedSubBlockStart.gifContractedSubBlock.gif        {
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
69ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
70        /// 更新员工信息事件
71        /// </summary>

72        public event EventHandler<EventArgs> UpdateEvent;
73        #endregion

74
75        protected void Page_Load(object sender, EventArgs e)
76ExpandedSubBlockStart.gifContractedSubBlock.gif        {
77            StaffDetailPresenter p = new StaffDetailPresenter(this);
78            p.InitializeView(IsPostBack);
79        }

80
81        protected void btn_Update(object sender, EventArgs e)
82ExpandedSubBlockStart.gifContractedSubBlock.gif        {
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

转载于:https://www.cnblogs.com/stalwart/archive/2011/03/16/1985963.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值