|
直接與間接
人們對(duì)于復(fù)雜的軟件系統(tǒng)常常有一種處理手法,即增加一層間接層,從而對(duì)系統(tǒng)獲得一種更為靈活、滿足特定需求的解決方案。
假設(shè)A要訪問(wèn)B三次。如果A和B是分布式中的兩個(gè)機(jī)器,那么A需要跨機(jī)器調(diào)用B三次就不是很好。如果在A和B之間加一個(gè)代理對(duì)象C,并且A和C處于同一個(gè)地址空間,即同一個(gè)機(jī)器。那么A和C之間通訊是非常高效的,現(xiàn)在A和C之間調(diào)用三次,到某個(gè)觸發(fā)點(diǎn)的時(shí)候,和B只需要一次的通訊,這樣性能就會(huì)好很多。這樣做還有一個(gè)好處,即A不需要再知道分布式通訊的內(nèi)容了。
現(xiàn)實(shí)生活中,其實(shí)操作系統(tǒng)就是軟件和硬件之間的代理。
動(dòng)機(jī)(Motivation)
在面向?qū)ο笙到y(tǒng)中,有些對(duì)象由于某種原因(比如對(duì)象創(chuàng)建的開(kāi)銷(xiāo)很大,或者某些操作需要安全控制,或者需要進(jìn)程外的訪問(wèn)等),直接訪問(wèn)會(huì)給使用者、或者系統(tǒng)結(jié)構(gòu)帶來(lái)很多麻煩。如何在不失去透明操作對(duì)象的同時(shí)來(lái)管理/控制這些對(duì)象特有的復(fù)雜性?增加一層間接層是軟件開(kāi)發(fā)中常見(jiàn)的解決方式。
意圖(Intent)
為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)。
——《設(shè)計(jì)模式》GoF
例說(shuō)Proxy應(yīng)用
HrSystem里面new的Employee對(duì)象將位于和HrSystem同樣的地址空間里面,但如果我們需要把Employee作為跨互聯(lián)網(wǎng)的調(diào)用,那么這樣的代碼就不適用了。改進(jìn)后的代碼:
Employee的代理應(yīng)該和Employee具有同樣的接口,它的實(shí)現(xiàn)很復(fù)雜。
其中,Employee類(lèi)運(yùn)行在InterNET遠(yuǎn)端的一臺(tái)機(jī)器上,而EmployeeProxy運(yùn)行在本地的Windows Forms上。這里代理的目的是為了屏蔽分布式通訊、WebService的細(xì)節(jié)。
結(jié)構(gòu)(Structure)
其中Subject就是HrSystem,它本來(lái)是要直接調(diào)用RealSubject的。但是由于WebSerivce這種情況,它需要間接的通過(guò)Proxy調(diào)用RealSubject。
Proxy模式的幾個(gè)要點(diǎn)
“增加一層間接層”是軟件系統(tǒng)中對(duì)許多復(fù)雜問(wèn)題的一種常見(jiàn)解決方法。在面向?qū)ο笙到y(tǒng)中,直接使用某些對(duì)象會(huì)來(lái)帶很多問(wèn)題,作為間接層的Proxy對(duì)象便是解決這一問(wèn)題的常用手段。具體Proxy設(shè)計(jì)模式的實(shí)現(xiàn)方法、實(shí)現(xiàn)粒度都相差很大,有些可能對(duì)單個(gè)對(duì)象做細(xì)粒度的控制,如copy-on-write技術(shù),有些可能對(duì)組件模塊提供抽象代理層,在架構(gòu)層次對(duì)對(duì)象做Proxy。
Proxy并不一定要求保持接口的一致性,只要能夠?qū)崿F(xiàn)間接控制,有時(shí)候損及一些透明性是可以接受的。
WebService的一些例子:
代理對(duì)象MathService
客戶端
客戶端使用的是MathService類(lèi),這個(gè)類(lèi)是在本地運(yùn)行的。
另一個(gè)例子:Copy-on-Write
左邊是堆,這樣做是比較浪費(fèi)內(nèi)存的,因?yàn)橄到y(tǒng)中可能有很多字符串重復(fù)。目前大多數(shù)系統(tǒng)都是以下的做法:
但這樣字符串就不能更改了,例如如果要把s1改為大寫(xiě),那么必須要另起一個(gè)字符串變量:
C#當(dāng)然也是允許對(duì)字符串更改的,不過(guò)不是string類(lèi)型,而是StringBuilder類(lèi)型。
這樣sb就可以被改變。StringBuilder的原理:
sb、sb2和sb3都指向同一個(gè)字符串,如果sb把里面內(nèi)容改變,那么就會(huì)把hello拷貝到另一塊內(nèi)存,再把內(nèi)容進(jìn)行更改。其實(shí)Copy-on-Write應(yīng)該更準(zhǔn)確地描述為Copy-on-Change。
StringBuilder其實(shí)就是一種代理,我們本意是想訪問(wèn)字符串的,StringBuilder就是一種可變字符串的代理,而且StringBuilder也沒(méi)有和String保持接口的一致性。我們看看StringBuilder的源代碼:
注意Replace方法,當(dāng)需要改變字符串的內(nèi)容時(shí),步驟是先new一個(gè)新的String,然后在更改新String的內(nèi)容。但如果只有一個(gè)StringBuilder,那么就不需要拷貝到新的區(qū)域,而是直接在原來(lái)的String上修改。
it知識(shí)庫(kù):C#面向?qū)ο笤O(shè)計(jì)模式縱橫談:Proxy 代理模式,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。