MVP模式是相似於MVC模式的一種設計模式,最近在作項目學習過程當中遇到,弄了好久終於有一些眉目,這是學習過程當中的一些筆記。
MVP指的是實體對象Model、視圖Viw和業務處理Presenter。MVP的做用是解耦UI渲染、業務邏輯和數據實體的關係。在普通的winform中,業務和界面是寫在一塊兒的,通常都是同一個Load或Click方法中,使View和Controller緊密聯繫。在MVP中,咱們將界面渲染放在View裏面,也就是winfrom的窗體應用類;將業務關係放在Presenter類中,這就是MVP中的業務數據類;最後的數據實體與數據庫的交互放在Model中,是三者各司其職。
通常的MVP中,咱們是在Presenter中主動使用View,也就是界面控件形態都是由Presenter去主動控制的。而創建這二者之間的聯繫,就是在Presenter中註冊View的事件,當界面發生由用戶觸發事件時,這個事件會經過View傳遞到Presenter中,並在Presenter中調用Model的數據方法,最後Presenter調用在類中引用的View的實例去改變界面形態,下面是一些方法的實現,這裏着重說明Presenter和View的關係。
首先,咱們定義View的接口類IView,裏面就一個數據實體的引用:數據庫
1 public interface IView<T>:IView 2 { 3 T Model { get; set; } 4 }
接下來,定義View的下一級接口,這裏是定義視圖一些控件和事件:設計模式
1 public interface IMainForm<T> : IView<T> 2 { 3 Button TestButton { get;} //定義MainFrom的按鈕引用 4 TextBox TestTextBox { get; } //定義MianForm的文本框引用 5 event EventHandler ViewLoadEvent; //定義窗體加載完畢執行事件 6 event EventHandler ButtonSubmitEvent; //定義按鈕事件 7 void ShowSubmitDialog(); //定義自定義的事件 8 }
最後就是View的實現類,裏面是實現的接口方法和屬性,包含一個按鈕及一個文本框,這裏有一個繼承了的MvpForm類和PresenterBinding的特性,一會再說:ide
1 [PresenterBinding(typeof(MainFormPresenter))] 2 public partial class MainForm : MvpForm , IMainForm<MainFormModel> 3 { 4 public MainForm() 5 { 6 InitializeComponent(); 7 } 8 9 public MainFormModel Model { get; set; } 10 public TextBox TestTextBox { get { return txtText; } } 11 public Button TestButton { get { return btnSubmit; } } 12 13 public event EventHandler ViewLoadEvent; 14 public event EventHandler ButtonSubmitEvent; 15 16 private void MainForm_Load(object sender, EventArgs e) 17 { 18 if (ViewLoadEvent != null) ViewLoadEvent(sender, e); 19 } 20 21 public void ShowSubmitDialog() 22 { 23 MessageBox.Show("to submit?"); 24 } 25 26 private void btnSubmit_Click(object sender, EventArgs e) 27 { 28 if (ButtonSubmitEvent != null) ButtonSubmitEvent(sender , e); 29 } 30 }
定義完View的內容,就能夠看一下Presenter,一樣,先有接口,再有實現,先定義Presenter的接口:函數
1 public interface IPresenter<T>:IPresenter where T : class, View.IView 2 { 3 T View { get; } 4 }
這裏再定義一個Presenter的抽象類,用於統一各個不一樣View對應的Presenter類,其定義以下:學習
1 public abstract class Presenter<T> : IPresenter<T> where T : class, View.IView 2 { 3 private readonly T view; 4 5 //這裏的view做爲引用,用於在presenter中獲取View的實例 6 protected Presenter(T view) 7 { 8 this.view = view; 9 } 10 11 public T View { get { return view; } } 12 }
最後就是對應的View的Presenter類了:this
1 class MainFormPresenter:Presenter<View.IMainForm<Model.MainFormModel>> 2 { 3 public MainFormPresenter(View.IMainForm<Model.MainFormModel> view) 4 : base(view) 5 { 6 view.Model = new Model.MainFormModel(); 7 8 view.ViewLoadEvent += On_ViewLoad; 9 view.ButtonSubmitEvent += On_ButtonSubmitClick; 10 init(); 11 } 12 13 public void init() 14 { 15 //To Do something... 16 } 17 18 public void On_ViewLoad(object sender, EventArgs e) 19 { 20 //To Do something... 21 } 22 23 public void On_ButtonSubmitClick(object sender, EventArgs e) 24 { 25 View.ShowSubmitDialog();//經過view的實例調用view的方法來改變控件形態 26 } 27 }
這裏定義了Presenter和View的接口和實現,下面就是如何將這兩個不一樣的模塊聯合在一塊兒,這裏,使用的是.net的特性和反射。
首先,先創建特性類PresenterBindingAttribute,經過在View的實現類標記該特性類和指定對應的Presenter類,就能夠獲取View和Presenter的對應關係了,該類一樣要標註特性AttributeUsage和繼承Attribute類,同時定義兩個屬性參數:spa
1 [AttributeUsage(AttributeTargets.Class,AllowMultiple = true)] 2 public sealed class PresenterBindingAttribute : Attribute 3 { 4 public Type PresenterType { get;private set; } 5 6 public Type ViewType { get; set; } 7 8 public PresenterBindingAttribute(Type presenterType) 9 { 10 PresenterType = presenterType; 11 ViewType = null; 12 } 13 }
接下來,就是經過反射去創建view和presenter的關係,這裏創建PerformBinding類:.net
1 public IPresenter PerformBinding(IView viewInstance) 2 { 3 IPresenter presenter = null; 4 Type t = viewInstance.GetType(); //獲取該視圖的類類型 5 object[] attrs = t.GetCustomAttributes(typeof(PresenterBindingAttribute), false); //獲取該類上的附加特性集合 6 //遍歷特性集合,找到Presenter類型附加的特性,經過該特性創建實例 7 foreach (PresenterBindingAttribute pba in attrs) 8 { 9 Type newt = pba.PresenterType; //獲取Presenter類類型 10 //創建Presenter實例,這裏的構造參數是View的對象,這樣就使二者創建了聯繫 11 Object obj = Activator.CreateInstance(pba.PresenterType, viewInstance); 12 presenter = obj as IPresenter; 13 } 14 return presenter; 15 }
那麼,這個類PerformBinding在哪裏使用,通常是在應用View啓動是就要註冊實例,這裏爲了解除類間的強耦合,就添加一箇中間類。在前面的View的實現類中,是繼承自一個MvpForm的類,這個MvpForm就使註冊View和Presenter關係的類,接下來看MvpForm的實現:設計
1 public partial class MvpForm : Form,IView 2 { 3 private readonly PresenterBinder presenterBinder = new PresenterBinder(); 4 public MvpForm() 5 { 6 presenterBinder.PerformBinding(this); //註冊關係 7 } 8 }
這樣,就創建了View與Presenter之間的關係,每次View頁面啓動,就先執行父類MvpForm的構造函數,註冊View和Presenter的關係,相應的邏輯能夠寫在Presenter中,View的做用就是做爲UI的渲染。之後添加View和Presenter實現類時,只須要繼承和實現相應的類和接口,並在View實現類添加相應的對應類特性,就可實現MVP的設計關係。3d