说到MVP模式就不得不说MVC模式,MVP其实是MVC的一个变体模式,那先说下这两者区别.
在MVP中View并不直接使用Model,它们之间的通信是通过Presenter(MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过Controller。
Model和View是完全隔离,由Presenter来完全Model和View之间的交互行为.
在MVC中虽然是通过Cotroller,但是View是可以直接访问Model的,从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示及View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。
这样看MVP的优点是非常明显的,但是这种模式就会导致View与Presenter之间产生的依赖就会比较大,如果View变化,可能就会导致Presenter变化,那这个有没有办法去降低这种依赖呢.
首先看下MVP的模型图
下面直接开始MVP的代码.
namespace MVPSimple.Model { public class CashBond { public string BondCode{ get; set; } public decimal ClearPrice{ get; set; } public decimal Total{ get; set; } } public class CashBondService { List<CashBond> cashBonds = new List<CashBond>(); public CashBondService() { } public CashBond GetCashBondByBondCode(string bondCode) { CashBond cash = //调用数据访问层,将数据提取出来 return cash; } public List<CashBond> GetAllCashBond() { //调用数据访问层,将数据提取出来 return cashBonds; } } } public interface ICurrentView { void AddAllCashBond(List<CashBond> cashs) void RemoveCashBond(string bondCode) } public class Presenter { private ICurrentView view; public Presenter(ICurrentView _view) { view = _view; } public void AddAllCashBondAction(string bondCode) { CashBondService service = new CashBondService() List<CashBond> cashs = service.GetAllCashBond() view.AddAllCashBond(cashs) } } public class CurrentForm : Form, ICurrentView { private Presenter presenter; public CurrentPage() { this.presenter = new Presenter(this); } public void AddAllCashBond(List<CashBond> cashs) { ListViewItem item = null; foreach(var cash in cashs) { item = new ListViewItem(); item.Text = cash.BondCode; item.SubItems.Add(cash.ClearPrice.ToString()); item.SubItems.Add(cash.Total.ToString()); this.lv.Items.Add(item); } } public void RemoveCashBond(string bondCode) { //do something } private void btnBind_Click(object sender, EventArgs e) { this.presenter.AddAllCashBondAction(); } }
上面的代码就是MVP的"标准"实现方式.在我理解中,MVP就是采用的中介者模式,将对象与对象之间的关联关系解耦,变"多个对象互相关联"为"多个对象和一个中介者关联".
但是大家看到其实View与Presenter还是有较大关联,在View中还是需要访问Presenter对象,那如何将各对象不直接和中介者进行耦合呢,也就是尽量弱化(不可能完全剔除)
View对Presenter的依赖。实际上,对于MVP来说,View仅仅向Presenter递交用户交互请求,使View无法直接显示访问Presenter以及Presenter成员.这通过事件订阅机制就可以了.
下面来扩展上面的代码.
public class CashBond : ICloneable { public string BondCode{ get; set; } public decimal ClearPrice{ get; set; } public decimal Total{ get; set; } object ICloneable.Clone() { return this.Clone(); } public CashBond Clone() { return new CashBond { BondCode = this.BondCode, ClearPrice = this.ClearPrice, Total = this.Total }; } } public class CashBondViewModel { List<CashBond> cashBonds = new List<CashBond>() { new CashBond{ BondCode= "001", ClearPrice= "100.00", Total= "1000000.00"}, new CashBond{ BondCode= "002", ClearPrice= "99.00", Total= "2000000.00"} } public CashBondViewModel() { } public CashBond GetCashBondByBondCode(string bondCode) { var cashs = from cash in cashBonds where cash.BondCode = bondCode select cash.Clone(); return cashs.ToList<CashBond>()[0]; } public List<CashBond> GetAllCashBond() { var cashs = from cash in cashBonds select cash.Clone(); return cashs.ToList<CashBond>(); } } public interface ICashBondView{ event EventHandler Load; event EventHandler<CashBondEventArgs> CashBondSelected; //定义了单条选择的事件,这个事件很重要 void ListAllCashBonds(List<CashBond> cashs); void DisplayCashBondInfo(CashBond cash); void Reset(); } public class CashBondEventArgs : EventArgs //继承EventArgs基类,以便于传参 { public string BondCode { get; set; } public CashBond Cash { get; set; } } public class Presenter<IView> { public IView View { get; private set; } public Presenter(IView view) { this.View = view; this.OnViewSet(); } protected virtual void OnViewSet() //此方法需要重写,注册各种事件 { } } public class CashBondPresenter : Presenter<ICashBondView> { public CashBondViewModel viewModel{ get; private set; } public CashBondPresenter(ICashBondView cashView) : base(cashView) { this.viewModel = new CashBondViewModel(); } protected override void OnViewSet() //重写并注册事件,一旦View中触发,就会执行里面的方法 { this.View.Load += (sender, e) => { List<CashBond> cashs = viewModel.GetAllCashBond(); this.View.ListAllCashBonds(cashs); }; this.View.CashBondSelected += (sender, e) => { CashBond cash = viewModel.GetCashBondByBondCode(e.BondCode); this.View.DisplayCashBondInfo(cash); } } } public partial class ViewBase : Form { private object _presenter; public ViewBase() { _presenter = this.CreatePresenter(); } protected virtual object CreatePresenter() { return null; } } public class CashBondView : ViewBase, ICashBondView { public CashBondView() { return new CashBondPresenter(this); } public event EventHandler<CashBondEventArgs> CashBondSelected; public void ListAllCashBonds(List<CashBond> cashs) { this.dgvCashBond.DataSource = cashs; } public void DisplayCashBondInfo(CashBond cash) { //do something } public void Reset() { //do something } protected virtual void OnCashBondSelected(string bondCode) { var prebondCode= this.textCashBondCode.Text.Trim(); if (bondCode == prebondCode) return; if (null != this.CashBondSelected) this.CashBondSelected(this, new CashBondEventArgs { BondCode = bondCode}); } private void dgvCashBond_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { var currentRow = this.dgvCashBond.Rows[e.RowIndex]; var bondCode = currentRow.Cells[0].Value.ToString(); this.OnCashBondSelected(bondCode); } }

浙公网安备 33010602011771号