C#設計模式之十二代理模式(Proxy Pattern)【結構型】
一、引言
今天我們要講【結構型】設計模式的第七個模式,也是“結構型”設計模式中的最後一個模式,該模式是【代理模式】,英文名稱是:Proxy Pattern。還是老套路,先從名字上來看看。“代理”可以理解為“代替”,代替“主人”做一些事情,為什麽需要“代理”,是因為某些原因(比如:安全方面的原因),不想讓“主人”直接面對這些繁瑣、復雜的問題,但是這些事情是經“主人”同意或者授意的,如同“主人”親自完成的一樣。這個模式很簡單,生活中的例子也很多。舉例說明,歌星、影星的經紀人就是現實生活中一個代理模式的很好例子,還有操作系統中的防火墻,也是代理的例子,要訪問系統,先過防火墻這關,否則免談。還有很多了,就不一一列舉了,大家在生活中慢慢的體會吧。
二、代理模式的詳細介紹
2.1、動機(Motivate)
在面向對象系統中,有些對象由於某種原因(比如對象創建的開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問等),直接訪問會給使用者、或者系統結構帶來很多麻煩。如何在不失去透明操作對象的同時來管理/控制這些對象特有的復雜性?增加一層間接層是軟件開發中常見的解決方式。
2.2、意圖(Intent)
為其他對象提供一種代理以控制對這個對象的訪問。 ——《設計模式》GoF
2.3、結構圖(Structure)
2.4、模式的組成
代理模式所涉及的角色有三個:
(1)、抽象主題角色(Subject)
(2)、代理主題角色(Proxy):代理主題角色內部含有對真實主題的引用,從而可以操作真實主題對象;代理主題角色負責在需要的時候創建真實主題對象;代理角色通常在將客戶端調用傳遞到真實主題之前或之後,都要執行一些其他的操作,而不是單純地將調用傳遞給真實主題對象。
(3)、真實主題角色(RealSubject):定義了代理角色所代表的真實對象。
附:在WCF或者WebService的開發過程中,我們在客戶端添加服務引用的時候,在客戶程序中會添加一些額外的類,在客戶端生成的類扮演著代理主題角色,我們客戶端也是直接調用這些代理角色來訪問遠程服務提供的操作。這個是遠程代理的一個典型例子。
2.5、代理模式的分類:
代理模式按照使用目的可以分為以下幾種:
(1)、遠程(Remote)代理:為一個位於不同的地址空間的對象提供一個局域代表對象。這個不同的地址空間可以是本電腦中,也可以在另一臺電腦中。最典型的例子就是——客戶端調用Web服務或WCF服務。
(2)、虛擬(Virtual)代理:根據需要創建一個資源消耗較大的對象,使得對象只在需要時才會被真正創建。
(3)、Copy-on-Write代理:虛擬代理的一種,把復制(或者叫克隆)拖延到只有在客戶端需要時,才真正采取行動。
(4)、保護(Protect or Access)代理:控制一個對象的訪問,可以給不同的用戶提供不同級別的使用權限。
(5)、防火墻(Firewall)代理:保護目標不讓惡意用戶接近。
(6)、智能引用(Smart Reference)代理:當一個對象被引用時,提供一些額外的操作,比如將對此對象調用的次數記錄下來等。
(7)、Cache代理:為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以這些結果。
在上面所有種類的代理模式中,虛擬代理、遠程代理、智能引用代理和保護代理較為常見的代理模式。
2.6、代理模式的具體實現
說起“代理模式”,其實很容易,現實生活中的例子也很多。明星的經紀人,國家的發言人都是代理的好例子。我們就用明星經紀人這個事情來介紹“代理模式”的實現吧。
1 namespace 代理模式的實現 2 { 3 /// <summary> 4 /// 大明星都有錢,有錢了,就可以請自己的經紀人了,有了經紀人,很多事情就不用自己親力親為。弄點緋聞,炒作一下子通過經紀人就可以名正言順的的操作了,萬一搞不好,自己也可以否認。 5 /// </summary> 6 class Client 7 { 8 static void Main(string[] args) 9 { 10 //近期,Fan姓明星關註度有點下降,來點炒作 11 AgentAbstract fan = new AgentPerson(); 12 fan.Speculation("偶爾出來現現身,為炒作造勢"); 13 14 Console.WriteLine(); 15 16 //過了段時間,又不行了,再炒作一次 17 fan.Speculation("這段時間不火了,開始離婚炒作"); 18 19 20 Console.Read(); 21 } 22 } 23 24 25 //該類型就是抽象Subject角色,定義代理角色和真實主體角色共有的接口方法 26 public abstract class AgentAbstract 27 { 28 29 //該方法執行具體的炒作---該方法相當於抽象Subject的Request方法 30 public virtual void Speculation(string thing) 31 { 32 Console.WriteLine(thing); 33 } 34 } 35 36 //該類型是Fan姓明星,有錢有勢,想炒什麽炒什麽---相當於具體的RealSubject角色 37 public sealed class FanStar : AgentAbstract 38 { 39 //有錢有勢,有背景啊 40 public FanStar() { } 41 42 //要有名氣,定期要炒作---就是RealSubject類型的Request方法 43 public override void Speculation(string thing) 44 { 45 Console.WriteLine(thing); 46 } 47 } 48 49 //該類型是代理類型----相當於具體的Proxy角色 50 public sealed class AgentPerson : AgentAbstract 51 { 52 //這是背後的老板, 53 private FanStar boss; 54 55 //老板在後面發號施令 56 public AgentPerson() 57 { 58 boss = new FanStar(); 59 } 60 61 //炒作的方法,執行具體的炒作---就是Proxy類型的Request方法 62 public override void Speculation(string thing) 63 { 64 Console.WriteLine("前期弄點緋聞,拍點野照"); 65 base.Speculation(thing); 66 Console.WriteLine("然後開發布會,傷心哭泣,繼續撈錢"); 67 } 68 } 69 }
這個模式很簡單,就話不多說了。
三、代理模式的實現要點:
“增加一層間接層”是軟件系統中對許多復雜問題的一種常見解決方法。在面向對象系統中,直接使用某些對象會來帶很多問題,作為間接層的Proxy對象便是解決這一問題的常用手段。具體Proxy設計模式的實現方法、實現粒度都相差很大,有些可能對單個對象做細粒度的控制,如copy-on-write技術,有些可能對組件模塊提供抽象代理層,在架構層次對對象做Proxy。
Proxy並不一定要求保持接口的一致性,只要能夠實現間接控制,有時候損及一些透明性是可以接受的。
3.1】、代理模式的優點:
(1)、代理模式能夠將調用用於真正被調用的對象隔離,在一定程度上降低了系統的耦合度;
(2)、代理對象在客戶端和目標對象之間起到一個中介的作用,這樣可以起到對目標對象的保護。代理對象可以在對目標對象發出請求之前進行一個額外的操作,例如權限檢查等。
不同類型的代理模式也具有獨特的優點,例如:
(1)、遠程代理為位於兩個不同地址空間對象的訪問提供了一種實現機制,可以將一些消耗資源較多的對象和操作移至性能更好的計算機上,提高系統的整體運行效率。
(2)、虛擬代理通過一個消耗資源較少的對象來代表一個消耗資源較多的對象,可以在一定程度上節省系統的運行開銷。
(3)、緩沖代理為某一個操作的結果提供臨時的緩存存儲空間,以便在後續使用中能夠共享這些結果,優化系統性能,縮短執行時間。
(4)、保護代理可以控制對一個對象的訪問權限,為不同用戶提供不同級別的使用權限。
3.2】、代理模式的缺點:
(1)、由於在客戶端和真實主題之間增加了一個代理對象,所以會造成請求的處理速度變慢
(2)、實現代理類也需要額外的工作,從而增加了系統的實現復雜度。
3.3】、代理模式的使用場景:
代理模式的類型較多,不同類型的代理模式有不同的優缺點,它們應用於不同的場合:
(1)、 當客戶端對象需要訪問遠程主機中的對象時可以使用遠程代理。
(2)、當需要用一個消耗資源較少的對象來代表一個消耗資源較多的對象,從而降低系統開銷、縮短運行時間時可以使用虛擬代理,例如一個對象需要很長時間才能完成加載時。
(3)、當需要為某一個被頻繁訪問的操作結果提供一個臨時存儲空間,以供多個客戶端共享訪問這些結果時可以使用緩沖代理。通過使用緩沖代理,系統無須在客戶端每一次訪問時都重新執行操作,只需直接從臨時緩沖區獲取操作結果即可。
(4)、 當需要控制對一個對象的訪問,為不同用戶提供不同級別的訪問權限時可以使用保護代理。
(5)、當需要為一個對象的訪問(引用)提供一些額外的操作時可以使用智能引用代理。
四、.NET 中代理模式的實現
代理模式在Net的FCL中的實現也不少,框架級別的有,類級別的也有。框架級別的有WCF,Remoting,他們都需要生成本地的代理,然後通過代理訪問進程外或者機器外的對象。類級別的有StringBuilder類型,StringBuilder其實就是一種代理,我們本意是想訪問字符串的,StringBuilder就是一種可變字符串的代理,而且StringBuilder也沒有和String保持接口的一致性。
五、總結
到今天為止,我們設計模式的三個部分講完兩個部分了,第一個部分是“創建型”的設計模式,解決對象創建的問題,對對象創建的解耦。第二部分就是“結構型”的設計模式,所謂結構型設計模式模式,顧名思義討論的是類和對象的結構 ,主要用來處理類或對象的組合。它包括兩種類型,一是類結構型模式,指的是采用繼承機制來組合接口或實現;二是對象結構型模式,指的是通過組合對象的方式來實現新的功能。它包括適配器模式、橋接模式、裝飾者模式、組合模式、外觀模式、享元模式和代理模式。設計模式到現在也說了不少了,但是看起來很多模式都很類似,之間好像很容轉換,有時候條件不同了,的確模式也可以轉換,但是不能肆意的轉換。為了避免思想的混亂,我們把“結構型”這個幾個設計模式,再總結一次,把握核心,理解使用場景。
適配器模式註重轉換接口,將不吻合的接口適配對接
橋接模式註重分離接口與其實現,支持多維度變化
組合模式註重統一接口,將“一對多”的關系轉化為“一對一”的關系
裝飾者模式註重穩定接口,在此前提下為對象擴展功能
外觀模式註重簡化接口,簡化組件系統與外部客戶程序的依賴關系
享元模式註重保留接口,在內部使用共享技術對對象存儲進行優化
代理模式註重假借接口,增加間接層來實現靈活控制
從下篇文章就開始寫“行為型”設計模式,今天就到此結束了。
C#設計模式之十二代理模式(Proxy Pattern)【結構型】