當需要控制對某個物件的存取、延遲昂貴物件的建立、記錄操作日誌、權限檢查、快取結果或遠端呼叫時,直接使用真實物件會導致客戶端程式碼混雜基礎設施邏輯。代理模式提供標準方案:為真實物件提供一個代理者,代理者實作相同介面,內部持有真實物件參考,在轉發呼叫前後插入額外邏輯。本文以訊息系統為例,展示代理模式如何透過 MessageProxy 控制對 SqlMessage 的存取。
IMessage,定義 Get()、Insert() 共同介面,代理與真實物件均實作此介面。SqlMessage,執行實際業務邏輯(SQL 查詢/插入)。MessageProxy,實作 IMessage,內部建立/持有 SqlMessage,轉發呼叫並可插入額外邏輯。
public interface IMessage
{
List<MessageModel> Get();
bool Insert(MessageModel mm);
}
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; }
}
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);
}
關鍵設計:
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
客戶端以相同方式使用代理與真實物件,驗證介面一致性。
隱藏網路通訊細節,客戶端呼叫本地代理,代理序列化參數發送 RPC 請求至遠端伺服器,反序列化結果回傳。
應用:Web Service Client、gRPC Stub、WCF Proxy、.NET Remoting。
延遲建立昂貴物件(大圖片、大型報表、資料庫連線),首次真正需要時才建立。
實作:Get() 中判斷 _sqlMessage == null 則 new SqlMessage()。
應用:圖片瀏覽器縮圖代理、OR/M 延遲載入導航屬性。
控制不同權限客戶端對真實物件的存取權限。
實作:Insert() 前檢查 Thread.CurrentPrincipal.IsInRole("Admin")。
應用:API Gateway 鑑權、資料庫 Row-Level Security 代理。
在存取真實物件前後執行額外動作:引用計數、鎖定、快取、日誌。
實作:Get() 先檢查快取,未命中則呼叫真實物件並存入快取。
應用:智慧指標、資源池管理、AOP 攔截器基礎。
EF Core 使用動態代理實現導航屬性延遲載入(virtual 屬性 + UseLazyLoadingProxies())。
Proxy 結尾,職責單一(一個代理一種關注點)。代理模式以「間接層」解決「直接存取」帶來的耦合與功能擴展難題。本範例以 MessageProxy 透明轉發 SqlMessage 為例,展示了代理模式最核心的結構:共同介面、真實主題、代理轉發。實務中,從遠端 RPC Stub 到 OR/M 延遲載入、從 API Gateway 鑑權到 AOP 攔截器,代理模式無處不在。掌握其四大變體(遠端、虛擬、保護、智慧引用)與現代實作技術(動態代理、Source Generator),能讓你在需要「控制存取、延遲初始化、橫切關注點分離」的系統設計中,選擇最適合的代理策略,構建出清晰分層、高內聚低耦合的架構。