代理模式(Proxy): 代理模式就是給某一個對象提供一個代理,並由代理對象控制對原有對象的引用。在一些情況下,一個客戶不想或者不能直接引用一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。例如windows桌面端的快捷方式就是一個代理。 代理模式按照使用目的可以分為: 1)遠程代理:為 ...
代理模式(Proxy):
代理模式就是給某一個對象提供一個代理,並由代理對象控制對原有對象的引用。在一些情況下,一個客戶不想或者不能直接引用一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。例如windows桌面端的快捷方式就是一個代理。
代理模式按照使用目的可以分為:
1)遠程代理:為一個位於不同的地址空間的對象提供一個局域代表對象。這個不同的地址空間可以是本電腦中,也可以在另一臺電腦中。如客戶端調用web服務或wcf服務。
2)虛擬代理:根據需要創建一個資源消耗較大的對象,使得對象只在需要時才會被真正創建。
3)Copy-on-Write代理:虛擬代理的一種,把複製(或克隆)拖延到只有在客戶端需要時,才真正採取行動。
4)保護(Protected or Access)代理:控制一個對象的訪問,可以給不同的用戶提供不同級別的使用許可權。
5)Cache代理:為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以操作這些結果。
6)防火牆(FireWall)代理:保護目標不讓惡意用戶接近。
7)同步化(Synchronization)代理
8)智能引用(Smart Reference)代理:當一個對象被引用時,提供一些額外的操作,比如將對此對象調用的次數記錄下來。
接下來以一個需求案例來說明下代理模式:
現有收費商務信息查詢系統的二次開發,增加需求:
1)添加用戶身份驗證;2)添加日誌記錄;3)要求以松耦合的方式進行功能添加
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 /* 6 * <?xml version="1.0" encoding="utf-8" ?> 7 * <configuration> 8 * <appSettings> 9 * <add key="proxy" value="Proxy,Proxy.ProxySearcher" /> 10 * </appSettings> 11 * </configuration> 12 */ 13 var proxy = ConfigurationManager.AppSettings["proxy"].Split(","); 14 var searcher = (Searcher)Assembly.Load(proxy[0]).CreateInstance(proxy[1]); 15 var result = searcher.DoSearch("楊過", "玉女心經"); 16 } 17 } 18 19 /// <summary> 20 /// (1) AccessValidator:身份驗證類,業務類,它提供方法Validate()來實現身份驗證。 21 /// </summary> 22 internal class AccessValidator 23 { 24 //模擬實現登錄驗證 25 public bool Validate(string userId) 26 { 27 Console.WriteLine($"在資料庫中驗證用戶{userId}是否是合法用戶?"); 28 if (userId.Equals("楊過")) 29 { 30 Console.WriteLine("'{0}'登錄成功!", userId); 31 return true; 32 } 33 else 34 { 35 Console.WriteLine("'{0}'登錄失敗!", userId); 36 return false; 37 } 38 } 39 } 40 41 /// <summary> 42 /// (2) Logger:日誌記錄類,業務類,它提供方法Log()來保存日誌。 43 /// </summary> 44 internal class Logger 45 { 46 //模擬實現日誌記錄 47 public void Log(string userId) 48 { 49 Console.WriteLine($"更新資料庫,用戶{userId}查詢次數加1!"); 50 } 51 } 52 53 /// <summary> 54 /// (3) Searcher:抽象查詢類,充當抽象主題角色,它聲明瞭DoSearch()方法。 55 /// </summary> 56 internal interface Searcher 57 { 58 string DoSearch(string userId, string keyWord); 59 } 60 61 /// <summary> 62 /// (4) RealSearcher:具體查詢類,充當真實主題角色,它實現查詢功能,提供方法DoSearch()來查詢信息。 63 /// </summary> 64 internal class RealSearcher : Searcher 65 { 66 public string DoSearch(string userId, string keyWord) 67 { 68 Console.WriteLine($"用戶{userId}使用關鍵詞{keyWord}查詢商務信息!"); 69 return "返回具體內容"; 70 } 71 } 72 73 /// <summary> 74 /// (5) ProxySearcher:代理查詢類,充當代理主題角色,它是查詢代理,維持了對RealSearcher對象、AccessValidator對象和Logger對象的引用。 75 /// </summary> 76 internal class ProxySearcher : Searcher 77 { 78 private Searcher searcher; 79 private AccessValidator validator; 80 private Logger logger; 81 82 public ProxySearcher() 83 { 84 searcher = new RealSearcher(); 85 } 86 87 public string DoSearch(string userId, string keyword) 88 { 89 //如果身份驗證成功,則執行查詢 90 if (this.Validate(userId)) 91 { 92 string result = searcher.DoSearch(userId, keyword); //調用真實主題對象的查詢方法 93 this.Log(userId); //記錄查詢日誌 94 return result; //返回查詢結果 95 } 96 else 97 { 98 return null; 99 } 100 } 101 102 //創建訪問驗證對象並調用其Validate()方法實現身份驗證 103 public bool Validate(string userId) 104 { 105 validator = new AccessValidator(); 106 return validator.Validate(userId); 107 } 108 109 //創建日誌記錄對象並調用其Log()方法實現日誌記錄 110 public void Log(string userId) 111 { 112 logger = new Logger(); 113 logger.Log(userId); 114 } 115 }
代理模式角色分四種:
1)主題介面(Searcher):定義代理類和真實主題的公共對外方法,也是代理類代理真實主題的方法;
2)真實主題(RealSeracher):真正實現業務邏輯的類;
3)代理類(ProxySeracher):用來代理和封裝真實主題;
4)客戶端:使用代理類和主題完成工作。
代理模式的優缺點:
優點:
1)代理模式能夠將調用用於真正被調用的對象隔離,在一定程度上降低了系統的耦合度;
2)代理對象在客戶端和目標對象之間起到一個中介的作用,這樣可以起到對目標對象的保護。代理對象可以在對目標對象發出請求之前進行一個額外的操作,例如許可權檢查等。
缺點:
1)由於在客戶端和真實主題之間增加了一個代理對象,所以會造成請求的處理速度變慢;
2)實現代理類也需要額外的工作,從而增加了系統的實現複雜度。
代理模式與適配器模式的區別?
學習完適配器模式和代理模式之後,會產生這樣的疑問:貌似兩種模式差不多?兩者都是定義了一個目標對象(抽象對象),客戶端依賴該抽象對象完成相應功能,這麼一解釋好像是一樣的,那為什麼大牛們會分成兩種模式呢?適配器模式是因為新舊介面不一致導致出現了客戶端無法得到滿足的問題,但由於舊的介面是不能被完全重構掉的,因為我們還想使用實現了這個介面的一些服務。那麼為了使用以前實現舊介面的服務,我們就應該把新的介面轉換成舊介面;實現這個轉換的類就是抽象意義的轉換器。相比於適配器的應用場景,代理就不一樣了,雖然代理也同樣是增加了一層,但是,代理提供的介面和原本的介面是一樣的,代理模式的作用是不把實現直接暴露給客戶端,而是通過代理這個層,代理能夠做一些處理。
代理模式與委托的區別?
1)代理是模式提供一種"一個類對另外一個類的控制權"是類與類之間關係;委托提供了"一種方法的執行會同時執行載入在上面的方法"是方法與方法之間的關係。
2)委托可以代替代理,但是代理不能代替委托。
3)委托可以動態載入方法,代理不能實現。
4)委托對象所載入的方法不一定要屬於同一個類。但是代理的類必須屬於同一個類。
參考:https://blog.csdn.net/lovelion/article/details/8228042
https://www.cnblogs.com/zhili/p/ProxyPattern.html
https://www.cnblogs.com/chenwolong/p/Proxy.html