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

C# 代理模式完全指南:控制物件存取與延遲初始化實戰

     編輯:關於C#

前言

當需要控制對某個物件的存取、延遲昂貴物件的建立、記錄操作日誌、權限檢查、快取結果或遠端呼叫時,直接使用真實物件會導致客戶端程式碼混雜基礎設施邏輯。代理模式提供標準方案:為真實物件提供一個代理者,代理者實作相同介面,內部持有真實物件參考,在轉發呼叫前後插入額外邏輯。本文以訊息系統為例,展示代理模式如何透過 MessageProxy 控制對 SqlMessage 的存取。

模式結構與三大角色

  • Subject(抽象主題):IMessage,定義 Get()、Insert() 共同介面,代理與真實物件均實作此介面。
  • RealSubject(真實主題):SqlMessage,執行實際業務邏輯(SQL 查詢/插入)。
  • Proxy(代理):MessageProxy,實作 IMessage,內部建立/持有 SqlMessage,轉發呼叫並可插入額外邏輯。
代理模式類別圖

核心程式碼機制深度解析

1. 抽象主題:定義共同契約

public interface IMessage
{
    List<MessageModel> Get();
    bool Insert(MessageModel mm);
}

2. 真實主題:核心業務實作

public class SqlMessage : IMessage
{
    public List<MessageModel> Get()
    {
        var l = new List<MessageModel>();
        l.Add(new MessageModel("SQL方式獲取Message", DateTime.Now));
        return l;
    }
    public bool Insert(MessageModel mm) { /* SQL 插入 */ return true; }
}

3. 代理:攔截與轉發

public class MessageProxy : IMessage
{
    private SqlMessage _sqlMessage;

    public MessageProxy()
    {
        _sqlMessage = new SqlMessage(); // 延遲初始化點:建構子/首次呼叫時建立
    }

    public List<MessageModel> Get() => _sqlMessage.Get();
    public bool Insert(MessageModel mm) => _sqlMessage.Insert(mm);
}

關鍵設計:

  • 代理實作相同介面,客戶端無感知差異(里氏替換原則)。
  • 建構子中建立真實物件(急切初始化),亦可改為首次呼叫時建立(延遲初始化)。
  • 轉發方法中可插入:日誌、權限檢查、快取、計數、重試、事務邊界等橫切關注點。

4. 客戶端:透明使用


MessageProxy m = new MessageProxy();
Response.Write(m.Insert(new MessageModel("插入", DateTime.Now)));
Response.Write(m.Get()[0].Message + " " + m.Get()[0].PublishTime);

執行結果驗證

True
SQL方式獲取Message 2007-4-1 16:31:24

客戶端以相同方式使用代理與真實物件,驗證介面一致性。

代理模式四大經典變體

1. 遠端代理

隱藏網路通訊細節,客戶端呼叫本地代理,代理序列化參數發送 RPC 請求至遠端伺服器,反序列化結果回傳。
應用:Web Service Client、gRPC Stub、WCF Proxy、.NET Remoting。

2. 虛擬代理

延遲建立昂貴物件(大圖片、大型報表、資料庫連線),首次真正需要時才建立。
實作:Get() 中判斷 _sqlMessage == null 則 new SqlMessage()。
應用:圖片瀏覽器縮圖代理、OR/M 延遲載入導航屬性。

3. 保護代理

控制不同權限客戶端對真實物件的存取權限。
實作:Insert() 前檢查 Thread.CurrentPrincipal.IsInRole("Admin")。
應用:API Gateway 鑑權、資料庫 Row-Level Security 代理。

4. 智慧引用代理

在存取真實物件前後執行額外動作:引用計數、鎖定、快取、日誌。
實作:Get() 先檢查快取,未命中則呼叫真實物件並存入快取。
應用:智慧指標、資源池管理、AOP 攔截器基礎。

.NET 生態中的代理實作技術

動態代理

  • Castle DynamicProxy:運行時生成代理類別,支援介面與虛擬方法攔截,AOP 框架基石。
  • DispatchProxy (.NET Core 內建):無第三方依賴,僅支援介面代理。
  • Autofac/Unity/Scrutor 攔截器:DI 容器整合,屬性/介面驅動自動代理。

原始碼生成器

  • Roslyn Source Generators:編譯期生成代理程式碼,零反射、高效能、支援 AOT。
  • 適用於:gRPC Client、最小化 API、序列化器、DI 代理。

實體框架導航屬性代理

EF Core 使用動態代理實現導航屬性延遲載入(virtual 屬性 + UseLazyLoadingProxies())。

優缺點與最佳實務

優點

  • 職責分離:真實物件專注業務,代理處理基礎設施。
  • 開閉原則:新增代理行為無需修改真實物件。
  • 客戶端透明:介面一致,無感遷移。
  • 支援多種變體組合(如:虛擬代理+保護代理+智慧引用)。

缺點

  • 增加間接層,可能影響效能(通常微乎其微)。
  • 若真實物件介面頻繁變更,代理需同步維護。
  • 過度使用導致「代理地獄」:層層包裝難以除錯。

最佳實務

  • 優先使用介面而非具體類別,便於代理替換。
  • 代理類別命名以 Proxy 結尾,職責單一(一個代理一種關注點)。
  • 複雜橫切關注點改用 AOP 框架(動態代理)而非手寫代理類別。
  • 文件化代理行為:延遲初始化條件、快取策略、權限規則、重試策略。

總結

代理模式以「間接層」解決「直接存取」帶來的耦合與功能擴展難題。本範例以 MessageProxy 透明轉發 SqlMessage 為例,展示了代理模式最核心的結構:共同介面、真實主題、代理轉發。實務中,從遠端 RPC Stub 到 OR/M 延遲載入、從 API Gateway 鑑權到 AOP 攔截器,代理模式無處不在。掌握其四大變體(遠端、虛擬、保護、智慧引用)與現代實作技術(動態代理、Source Generator),能讓你在需要「控制存取、延遲初始化、橫切關注點分離」的系統設計中,選擇最適合的代理策略,構建出清晰分層、高內聚低耦合的架構。


參考資源:DoFactory Proxy Pattern

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