首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

淺析 MVP 模式中 View-Presenter 交互問題與最佳實踐案例

     編輯:ASP.NET 基礎

MVP 模式回顧

MVP(Model-View-Presenter)是表現層設計模式,將 UI 模塊劃分為三個角色:

  • Model:業務邏輯與數據提供者。
  • View:負責數據可視化呈現與用戶交互事件觸發,實現特定接口(IView)。
  • Presenter:協調 Model 與 View,處理 UI 邏輯、調用業務、操作視圖更新。

Passive View(被動視圖)變體中,View 與 Model 不直接交互,完全通過 Presenter 中介。View 應盡可能「被動」:僅報告用戶動作、接收 Presenter 推送的數據,不主動拉取、不持有業務狀態。

常見反模式:Presenter 淪為 Proxy

許多項目中,開發者將大量 UI 邏輯寫在 View(代碼後置),Presenter 僅做簡單轉發調用 Model,實際上 Presenter 成了 Model 在 View 端的代理。判斷標準:View 代碼行數遠大於 Presenter,且 View 直接調用 Presenter 方法而非觸發事件。

改進方案:事件驅動解耦 View 對 Presenter 的依賴

核心思想:View 不持有 Presenter 引用,通過事件發布用戶動作;Presenter 訂閱 View 事件並處理。 通過基類框架強制實現:

1. View 基類


public abstract class ViewBase : Form
{
    private object _presenter;
    public ViewBase() { _presenter = CreatePresenter(); }
    protected abstract object CreatePresenter(); // 具體 View 必須實現,返回 Presenter 實例
}

2. Presenter 基類


public class Presenter where TView : class
{
    public TView View { get; private set; }
    public Presenter(TView view) { View = view; OnViewSet(); }
    protected virtual void OnViewSet() { } // 子類重寫註冊事件
}

3. View 接口基類


public interface IViewBase
{
    event EventHandler Load;
    event EventHandler Closed;
    event CancelEventHandler Closing;
}

完整案例:客戶信息管理

Model


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) { /* 更新邏輯 */ }
}

View 接口


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; }

Presenter


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("更新成功"); 
        };
    }
}

具體 View (WinForm)


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}); }
}

優勢總結

  • View 零依賴 Presenter,無法誤調用業務邏輯,強制 Passive View。
  • Presenter 掌握完整控制流,便於單元測試(Mock IView/IModel)。
  • View 可輕鬆替換(WebForm/WPF/Console)無需改動 Presenter。
  • 框架層統一生命週期,減少樣板代碼。

此模式適用於 WinForms、WPF 等富客戶端開發;Web Forms 雖可借鑑,但受限於無狀態 HTTP,通常採用 MVP 變體或 MVC。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved