MVP(Model-View-Presenter)是表現層設計模式,將 UI 模塊劃分為三個角色:
IView)。Passive View(被動視圖)變體中,View 與 Model 不直接交互,完全通過 Presenter 中介。View 應盡可能「被動」:僅報告用戶動作、接收 Presenter 推送的數據,不主動拉取、不持有業務狀態。
許多項目中,開發者將大量 UI 邏輯寫在 View(代碼後置),Presenter 僅做簡單轉發調用 Model,實際上 Presenter 成了 Model 在 View 端的代理。判斷標準:View 代碼行數遠大於 Presenter,且 View 直接調用 Presenter 方法而非觸發事件。
核心思想:View 不持有 Presenter 引用,通過事件發布用戶動作;Presenter 訂閱 View 事件並處理。 通過基類框架強制實現:
public abstract class ViewBase : Form
{
private object _presenter;
public ViewBase() { _presenter = CreatePresenter(); }
protected abstract object CreatePresenter(); // 具體 View 必須實現,返回 Presenter 實例
}
public class Presenter where TView : class
{
public TView View { get; private set; }
public Presenter(TView view) { View = view; OnViewSet(); }
protected virtual void OnViewSet() { } // 子類重寫註冊事件
}
public interface IViewBase
{
event EventHandler Load;
event EventHandler Closed;
event CancelEventHandler Closing;
}
public class Customer { public string Id, FirstName, LastName, Address; }
public class CustomerModel
{
private List _list = new List { ... };
public Customer[] GetAll() => _list.Select(c => c.Clone()).ToArray();
public Customer GetById(string id) => _list.First(c => c.Id == id).Clone();
public void Update(Customer c) { /* 更新邏輯 */ }
}
public interface ICustomerView : IViewBase
{
event EventHandler CustomerSelected;
event EventHandler CustomerSaving;
void ListAllCustomers(Customer[] customers);
void DisplayCustomerInfo(Customer customer);
void Clear();
}
public class CustomerEventArgs : EventArgs { public string CustomerId; public Customer Customer; }
public class CustomerPresenter : Presenter
{
public CustomerModel Model { get; } = new CustomerModel();
public CustomerPresenter(ICustomerView view) : base(view) { }
protected override void OnViewSet()
{
View.Load += (s, e) => { View.ListAllCustomers(Model.GetAll()); View.Clear(); };
View.CustomerSelected += (s, e) => View.DisplayCustomerInfo(Model.GetById(e.CustomerId));
View.CustomerSaving += (s, e) =>
{
Model.Update(e.Customer);
View.ListAllCustomers(Model.GetAll());
View.Clear();
MessageBox.Show("更新成功");
};
}
}
public partial class CustomerView : ViewBase, ICustomerView
{
public CustomerView() { InitializeComponent(); }
protected override object CreatePresenter() => new CustomerPresenter(this);
// 實現接口成員:事件、綁定方法、清空方法...
// 控件事件中僅觸發接口事件:
private void grid_RowHeaderMouseClick(...) { OnCustomerSelected(id); }
private void btnOK_Click(...) { OnCustomerSaving(customer); }
protected virtual void OnCustomerSelected(string id) { CustomerSelected?.Invoke(this, new CustomerEventArgs{CustomerId=id}); }
protected virtual void OnCustomerSaving(Customer c) { CustomerSaving?.Invoke(this, new CustomerEventArgs{Customer=c}); }
}
此模式適用於 WinForms、WPF 等富客戶端開發;Web Forms 雖可借鑑,但受限於無狀態 HTTP,通常採用 MVP 變體或 MVC。