引言
在我們的生活中,經常會遇到需要什么東西,但是自己又不是很方便或者對方不是很方便,則就需要中間的一個代理人去解決。例如代購。
在軟件開發中,也會遇到這樣的問題。有些對象有時候會由於網絡或其他的障礙,以至於不能夠或者不能直接訪問到這些對象,如果直接訪問對象給系統帶來不必要的復雜性,這時候可以在客戶端和目標對象之間增加一層中間層,讓代理對象代替目標對象,然后客戶端只需要訪問代理對象,由代理對象去幫我們去請求目標對象並返回結果給客戶端,這樣的一個解決思路就是今天要介紹的代理模式。
概念
代理是一種結構型設計模式, 讓你能提供真實服務對象的替代品給客戶端使用。 代理接收客戶端的請求並進行一些處理 (訪問控制和緩存等), 然后再將請求傳遞給服務對象。
代理對象擁有和服務對象相同的接口, 這使得當其被傳遞給客戶端時可與真實對象互換。
結構圖
代理模式所涉及的角色有三個:
抽象主題角色(Person):聲明了真實主題和代理主題的公共接口,這樣一來在使用真實主題的任何地方都可以使用代理主題。
代理主題角色(Friend):代理主題角色內部含有對真實主題的引用,從而可以操作真實主題對象;代理主題角色負責在需要的時候創建真實主題對象;代理角色通常在將客戶端調用傳遞到真實主題之前或之后,都要執行一些其他的操作,而不是單純地將調用傳遞給真實主題對象。例如這里的PreBuyProduct和PostBuyProduct方法就是代理主題角色所執行的其他操作。
真實主題角色(RealBuyPerson):定義了代理角色所代表的真是對象。
分類
代理模式按照使用目的可以分為以下幾種:
- 遠程(Remote)代理:為一個位於不同的地址空間的對象提供一個局域代表對象。這個不同的地址空間可以是本電腦中,也可以在另一台電腦中。最典型的例子就是——客戶端調用Web服務或WCF服務。
- 虛擬(Virtual)代理:根據需要創建一個資源消耗較大的對象,使得對象只在需要時才會被真正創建。
- Copy-on-Write代理:虛擬代理的一種,把復制(或者叫克隆)拖延到只有在客戶端需要時,才真正采取行動。
- 保護(Protect or Access)代理:控制一個對象的訪問,可以給不同的用戶提供不同級別的使用權限。
- 防火牆(Firewall)代理:保護目標不讓惡意用戶接近。
- 智能引用(Smart Reference)代理:當一個對象被引用時,提供一些額外的操作,比如將對此對象調用的次數記錄下來等。
- Cache代理:為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以這些結果。
在上面所有種類的代理模式中,虛擬代理、遠程代理、智能引用代理和保護代理較為常見的代理模式。
實現
例如項目A的PM需要購買一個測試工具,但是測試工具的運營商在國外,自己過去不是很方便,所以需要找一個代理商幫助自己去購買。
下面就實現此購買的例子:
using System; namespace Proxy { class Program { static void Main(string[] args) { ProgramManagement PM = new ProgramManagement(); PM.BuyToolName = "Bug管理工具"; PM.BuyTestTool(); ProxyBuyTestTool Tynam = new ProxyBuyTestTool(PM); Tynam.BuyTestTool(); Console.ReadKey(); } } public interface ITestTool { void BuyTestTool(); } public class ProgramManagement : ITestTool { public string BuyToolName; public void BuyTestTool() { Console.WriteLine($"項目A需要找一個代理商購買國外的一款{this.BuyToolName}的測試工具"); } } public class ProxyBuyTestTool : ITestTool { private ProgramManagement _pm; public ProxyBuyTestTool(ProgramManagement pm) { this._pm = pm; } public void BuyTestTool() { Console.WriteLine($"幫助項目A購買測試工具{this._pm.BuyToolName}成功"); } } }
運行后結果
項目A需要找一個代理商購買國外的一款Bug管理工具的測試工具
幫助項目A購買測試工具Bug管理工具成功
使用場景
當無法或不想直接引用某個對象或訪問某個對象存在困難時,可以通過代理對象來間接訪問。使用代理模式主要有兩個目的:一是保護目標對象,二是增強目標對象。
由於代理模式有許多分類,應用場景又適於多種情況:
- 遠程代理,這種方式通常是為了隱藏目標對象存在於不同地址空間的事實,方便客戶端訪問。例如,用戶申請某些網盤空間時,會在用戶的文件系統中建立一個虛擬的硬盤,用戶訪問虛擬硬盤時實際訪問的是網盤空間。
- 虛擬代理,這種方式通常用於要創建的目標對象開銷很大時。例如,下載一幅很大的圖像需要很長時間,因某種計算比較復雜而短時間無法完成,這時可以先用小比例的虛擬代理替換真實的對象,消除用戶對服務器慢的感覺。
- 安全代理,這種方式通常用於控制不同種類客戶對真實對象的訪問權限。
- 智能指引,主要用於調用目標對象時,代理附加一些額外的處理功能。例如,增加計算真實對象的引用次數的功能,這樣當該對象沒有被引用時,就可以自動釋放它。
- 延遲加載,指為了提高系統的性能,延遲對目標的加載。例如,Hibernate 中就存在屬性的延遲加載和關聯表的延時加載。
優缺點
優點:
- 代理模式在客戶端與目標對象之間起到一個中介作用和保護目標對象的作用。
- 代理對象可以擴展目標對象的功能。
- 代理模式能將客戶端與目標對象分離,在一定程度上降低了系統的耦合度,增加了程序的可擴展性。
缺點:
- 代理模式會造成系統設計中類的數量增加。
- 在客戶端和目標對象之間增加一個代理對象,會造成請求處理速度變慢。
- 增加了系統的復雜度。