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


 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}

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

Code

第四步,定义员工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 nullreturn 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

原文地址:https://www.cnblogs.com/stalwart/p/1985963.html