15.3 代理模式應用執行個體
下面通過一個應用執行個體來進一步學習和理解代理模式。
1. 執行個體說明
某軟體公司承接了某資訊諮詢公司的收費商務資訊查詢系統的開發工作單位,該系統的基本需求如下: (1) 在進行商務資訊查詢之前使用者需要通過身分識別驗證,只有合法使用者才能夠使用該查詢系統; (2) 在進行商務資訊查詢時系統需要記錄查詢日誌,以便根據查詢次數收取查詢費用。 該軟體公司開發人員已完成了商務資訊查詢模組的開發工作單位,現希望能夠以一種松耦合的方式向原有系統增加身分識別驗證和日誌記錄功能,用戶端代碼可以無區別地對待原始的商務資訊查詢模組和增加新功能之後的商務資訊查詢模組,而且可能在將來還要在該資訊查詢模組中增加一些新的功能。 試使用代理模式設計並實現該收費商務資訊查詢系統。 |
2. 執行個體分析及類圖
通過分析,可以採用一種間接訪問的方式來實現該商務資訊查詢系統的設計,在用戶端對象和資訊查詢對象之間增加一個代理對象,讓代理對象來實現身分識別驗證和日誌記錄等功能,而無須直接對原有的商務資訊查詢對象進行修改,15-3所示:
圖15-3 商務資訊查詢系統設計方案
在圖15-3中,用戶端對象通過代理對象間接訪問具有商務資訊查詢功能的真實對象,在代理對象中除了調用真實對象的商務資訊查詢功能外,還增加了身分識別驗證和日誌記錄等功能。使用代理模式設計該商務資訊查詢系統,結構圖15-4所示。
圖15-4 商務資訊查詢系統結構圖
在圖15-4中,業務類AccessValidator用於驗證使用者身份,業務類Logger用於記錄使用者查詢日誌,Searcher充當抽象主題角色,RealSearcher充當真實主題角色,ProxySearcher充當代理主題角色。
3. 執行個體代碼
(1) AccessValidator:身分識別驗證類,業務類,它提供方法Validate()來實現身分識別驗證。
//AccessValidator.csusing System;namespace ProxySample{ class AccessValidator { //類比實現登入驗證 public bool Validate(string userId) { Console.WriteLine("在資料庫中驗證使用者'" + userId + "'是否是合法使用者?"); if (userId.Equals("楊過")) { Console.WriteLine("'{0}'登入成功!",userId); return true; } else { Console.WriteLine("'{0}'登入失敗!", userId); return false; } } }}
(2) Logger:日誌記錄類,業務類,它提供方法Log()來儲存日誌。
//Logger.csusing System;namespace ProxySample{ class Logger { //類比實現日誌記錄 public void Log(string userId) { Console.WriteLine("更新資料庫,使用者'{0}'查詢次數加1!",userId); } }}
(3) Searcher:抽象查詢類,充當抽象主題角色,它聲明了DoSearch()方法。
//Searcher.csnamespace ProxySample{ interface Searcher { string DoSearch(string userId, string keyword); }}
(4) RealSearcher:具體查詢類,充當真實主題角色,它實現查詢功能,提供方法DoSearch()來查詢資訊。
//RealSearcher.csusing System;namespace ProxySample{ class RealSearcher : Searcher { //類比查詢商務資訊 public string DoSearch(string userId, string keyword) { Console.WriteLine("使用者'{0}'使用關鍵詞'{1}'查詢商務資訊!",userId,keyword); return "返回具體內容"; } }}
(5) ProxySearcher:代理查詢類,充當代理主題角色,它是查詢代理,維持了對RealSearcher對象、AccessValidator對象和Logger對象的引用。
//ProxySearcher.csnamespace ProxySample{ class ProxySearcher : Searcher { private RealSearcher searcher = new RealSearcher(); //維持一個對真實主題的引用 private AccessValidator validator; private Logger logger; public string DoSearch(string userId, string keyword) { //如果身分識別驗證成功,則執行查詢 if (this.Validate(userId)) { string result = searcher.DoSearch(userId, keyword); //調用真實主題對象的查詢方法 this.Log(userId); //記錄查詢日誌 return result; //返回查詢結果 } else { return null; } } //建立訪問驗證對象並調用其Validate()方法實現身分識別驗證 public bool Validate(string userId) { validator = new AccessValidator(); return validator.Validate(userId); } //建立日誌記錄對象並調用其Log()方法實現日誌記錄 public void Log(string userId) { logger = new Logger(); logger.Log(userId); } }}
(6) 設定檔App.config,在設定檔中儲存了代理主題類類名。
<?xml version="1.0" encoding="utf-8" ?><configuration> <appSettings> <add key="proxy" value="ProxySample.ProxySearcher"/> </appSettings></configuration>
(7) Program:用戶端測試類別
//Program.csusing System;using System.Configuration;using System.Reflection;namespace ProxySample{ class Program { static void Main(string[] args) { //讀取設定檔 string proxy = ConfigurationManager.AppSettings["proxy"]; //反射產生對象,針對抽象編程,用戶端無須分辨真實主題類和代理類 Searcher searcher; searcher = (Searcher)Assembly.Load("ProxySample").CreateInstance(proxy); String result = searcher.DoSearch("楊過", "玉女心經"); Console.Read(); } }}
4. 結果及分析
編譯並運行程式,輸出結果如下:
在資料庫中驗證使用者'楊過'是否是合法使用者? '楊過'登入成功! 使用者'楊過'使用關鍵詞'玉女心經'查詢商務資訊! 更新資料庫,使用者'楊過'查詢次數加1! |
本執行個體是保護代理和智能引用代理的應用執行個體,在代理類ProxySearcher中實現對真實主題類的許可權控制和引用計數,如果需要在訪問真實主題時增加新的存取控制機制和新功能,只需增加一個新的代理類,再修改設定檔,在用戶端代碼中使用新增代理類即可,原始碼無須修改,符合開閉原則。
【作者:劉偉(Sunny) http://blog.csdn.net/lovelion】