MVP之V和P的交互

三者之間的關係html

在MVP初探裏簡單的描述了V和P之間是如何交互的。前端

不管是PV仍是SC,M\V\P這三者之間的關係並無發生改變,V只是前端的客戶代理承現展顯數據,P是如何處理客戶交互行爲的決策者。編程

數據是P主動「推」給V的,而V只向P發送用戶通知,都是單向的;因此在IView中被Presenter調用的方法應該都是沒有返回值的。能夠經過調用IView中的方法,也能夠經過事件註冊的方式來實現P/V之間的交互。ide

那麼,在PV模式下View是被動的,而P則控制着對V請求的處理;view僅將用戶的(事件)請求提交到P,它並不參與對用戶請求的處理,若是在這個過程當中P要V參與(如:顯示實時的數據等)也是P將要展示的數據PUSH到V,對於處理的結果的呈現也是一樣的處理方式。函數

而P在此過程當中的角色是一個決策者,它決定如何處理V提交過來的用戶請求,如何去實現業務邏輯和調用Model。post

如何維護三者的關係this

View僅是傳遞用戶請求和對數據的呈現;Presenter是事件的的決策者;Model業務邏輯執行者。spa

在PV中三者的關係使用的uView能夠直接調用Presenter,這樣就會使用的在開發過程當中將Presenter做爲View和Model之間的一種代理(Proxy)而不是Presenter.代理

那麼咱們就能夠經過事件訂閱機制來解決這個問題。code

編程模型的實現

首先,要讓View不能訪問到Presenter,咱們能夠經過事件訂閱機制;爲全部的Presenter建立基類Presenter<IView>,泛型類型IView表示具體View實現的接口。表示View的同名只讀屬性在構造函數中賦值,賦值完成以後調用調用虛方法OnViewSet,使得對具體的Presenter能夠重寫該方法進行對View進行事件註冊工做。

 1 namespace Handwe.Demo.MVP
 2 {
 3    public class Presenter<IView>
 4     {
 5        public IView View { get; set; }  
 6 
 7        public Presenter(IView view){
 8            this.View = view;
 9            this.OnViewSet();
10        }
11 
12        protected virtual void OnViewSet()
13        {
14 
15        }
16     }
17 }

 其次,Presenter是經過接口的方式與View進行交互的。有時候咱們要經過這個接口訪問Form的一些屬性、方法和事件,須要將相應的成員定義在接口上面,可能會有不少,添加的刪減等。那麼,咱們能夠將這些成員定義在一個接口中,具體View的接口繼承該接口就能夠了。在這裏,咱們至關是爲全部的View接口建立了「基接口」。以下:

 1 namespace Handwe.Demo.MVP
 2 {
 3     public interface IViewBase
 4     {
 5         event EventHandler Load;
 6         event EventHandler Closed;
 7         event CancelEventHandler Closing;
 8 
 9         string ResultText
10         {
11             get;set;
12         }
13 
14     }
15 }

同時,也要建立全部的View建立基類ViewBase,作必要的初始化工做,如加載基礎數據等:

 1 namespace Handwe.Demo.MVP
 2 {
 3     public class ViewBase : Form
 4     {
 5         public ViewBase()
 6         {
 7             this.CreatePresenter();
 8         }
 9 
10         protected virtual object CreatePresenter()
11         {
12             if (LicenseManager.CurrentContext.UsageMode == LicenseUsageMode.Designtime)
13             {
14                 return null;
15             }
16             else
17             {
18                 throw new NotImplementedException(string.Format("{0} must override the CreatedPresenter method.", this.GetType().FullName));
19             }
20         }
21     }
22 }

 在ViewBase中調用CreatedPresenter(),它的實如今具體的每一個View中也就是實現Presenter和View對應;

1 public partial class CalculatorView : ViewBase, ICalculatorView
2 ...
3 protected override object CreatePresenter()
4         {
5             return new CalculatePresenter(this);
6         }
7
8 ...
9 }

實例的實現:

那邊如今能夠定義View的接口ICalculatorView,在這裏定義了一個事件Calculating,也就是點擊btnCalculate觸發,還要定義三個方法,DisplayResult(int result)、DisplayMsg(stirng msg)、還有一個是Clear();具體什麼用途看名稱就知道了,以下:

 1 namespace Handwe.Demo.UnityInMVP
 2 {
 3     public interface ICalculatorView : IViewBase
 4     {
 5         event EventHandler<CalculateEventArgs> Calculating;
 6 
 7 
 8         void DisplayResult(int result);
 9 
10         void DisplayMsg(string msg);
11 
12         void Clear();
13     }
14 }

這裏有一個CalculateEventArgs,它是自定義的事件參數類型:

1 namespace Handwe.Demo.UnityInMVP
2 {
3     public class CalculateEventArgs : EventArgs
4     {
5         public string OperationNum1 { get; set; }
6 
7         public string OperationNum2 { get; set; }
8     }
9 }

很簡單隻定義了兩個屬性;

 接着來實現CalculatorView,代碼以下:

 1 namespace Handwe.Demo.UnityInMVP
 2 {
 3     public partial class CalculatorView : ViewBase, ICalculatorView
 4     {
 5         public CalculatorView()
 6         {
 7             InitializeComponent();
 8         }
 9         
10         public string ResultText
11         {
12             get { return this.labResult.Text; } set{this.labResult.Text = value;}
13         }
14 
15         protected override object CreatePresenter()
16         {
17             return new CalculatorPresenter();
18 } 19 20 #region ICalculateView Members 21 public event EventHandler<CalculateEventArgs> Calculating; 22 23 public void DisplayResult(int result) 24 { 25 this.textBoxResult.Text = result.ToString(); 26 } 27 28 public void Clear() 29 { 30 this.textBoxOp1.Text = string.Empty; 31 this.textBoxOp2.Text = string.Empty; 32 33 this.DisplayMsg(string.Empty); 34 } 35 36 public void DisplayMsg(string msg) 37 { 38 this.labDisplayMsg.Text = msg; 39 } 40 #endregion 41 42 private void btnCalculate_Click(object sender, EventArgs e) 43 { 44 string op1 = this.textBoxOp1.Text.Trim(); 45 string op2 = this.textBoxOp2.Text.Trim(); 46 this.OnCalculating(op1, op2); 47 } 48 49 private void btnClear_Click(object sender, EventArgs e) 50 { 51 } 52 53 private void btnCheck_Click(object sender, EventArgs e) 54 { 55 } 56 57 protected virtual void OnCalculating(string op1, string op2) 58 { 59 if (null != this.Calculating) 60 { 61 this.Calculating(this, new CalculateEventArgs { OperationNum1 = op1, OperationNum2 = op2 }); 62 } 63 } 64 } 65 }

而後咱們實現事件的訂閱者,這裏就是CalculatePresenter:

 1 namespace Handwe.Demo.UnityInMVP
 2 {
 3     public class CalculatePresenter : Presenter<ICalculatorView>
 4     {
 5         public CalculatePresenter(ICalculatorView view):base(view)
 6         {
 7             this.Calculate = new Calculate();
 8         }
 9
10
11 public Calculate Calculate 12 { 13 get; 14 set; 15 } 16 17 protected override void OnViewSet() 18 { 19 this.View.Load += (sender, args) => 20 { 21 22 this.View.Clear(); 23 }; 24 25 this.View.Calculating += (sender, args) => 26 { 27 int op1, op2; 28 if (!int.TryParse(args.OperationNum1, out op1)) 29 { 30 this.View.DisplayMsg(string.Format("{0} type invalid.", args.OperationNum1)); 31 return; 32 } 33 34 if (!int.TryParse(args.OperationNum2, out op2)) 35 { 36 this.View.DisplayMsg(string.Format("{0} type invalid.", args.OperationNum1)); 37 return; 38 } 39 int result = this.Calculator.Divide(op1, op2); 40 41 this.View.DisplayResult(result); 42 43 this.View.Clear(); 44 this.View.DisplayMsg("please type operation numbers."); 45 }; 46 } 47 } 48 }

至此,Calculator演示實例已基本完成了,下篇將會在這個實例的基礎上引入Unity、PIAB、Exception Handling,實現對Calculate的解耦和異常處理。《Unity、PIAB、Exception Handling引入MVP

http://www.cnblogs.com/coble/p/5646717.html

相關文章
相關標籤/搜索