在前一回中,我們介紹了Dummy Object及Mock Object,接下來,讓我們繼續探索,看看究竟還有什麼樣的「模仿型」物件。

什麼是Proxy物件?
首先要介紹的是所謂的「Proxy」。Proxy這個名詞大家恐怕都不陌生,在網際網路的術語中,Proxy是代理的意思,例如HTTP Proxy可以代理我們的瀏覽器在瀏覽遠端網站時的一些動作,介於其中提供額外的作用,例如提供快取的功能,來加快瀏覽器瀏覽網頁時的速度。而在物件導向設計的領域中,Proxy同樣意指代理,它所代表的是某個物件扮演「代理」另一個物件的角色。

因為Proxy物件是做為本尊物件的代理人,所以,它必須提供本尊物件原先提供的服務。但是,既然本尊物件自身就能提供服務了,那為什麼需要它額外居於其中做代理的工作呢?當然,代理人的存在都有其價值,在物件導向設計的世界中亦然。

Proxy物件,依據其做為「代理」角色的差異,分別提供了不同的作用,當然,也就具備了各自的價值。在更進一步介紹各類Proxy物件之前,讓我們先來看看Proxy的共通行為。

不論是那一種Proxy,每個Proxy物件背後都對應到一個真正提供服務的物件,也就是說,真正的工作都是由後端的本尊物件來執行、完成。但客戶端的程式碼(client code),只會接觸到Proxy物件,而不會接觸到Proxy背後、真正能提供服務的本尊物件。

只有Proxy物件才能真正的接觸到本尊物件,因為Proxy是本尊物件的代理人,想要存取本尊物件所提供的服務,只有一個途徑,也就是透過它的代理人。由於Proxy物件的長相和本尊物件相同(當然,它是模仿型物件),所以客戶端程式碼可以呼叫Proxy物件的函式,就如同呼叫本尊物件的函式。

Proxy物件終究只是代理不是本尊,所以,Proxy物件最終還是必須借助本尊物件之力才能達成客戶端程式碼期許完成的工作。所以當客戶端程式碼呼叫Proxy物件的函式時,Proxy物件最終還是得呼叫本尊物件的函式。所以,Proxy物件大概都有類似這樣的實作:


Proxy物件(SomethingProxy)提供了和本尊物件(Something)相同的介面,所以有著相同的函式,也就能提供和本尊物件相同的服務。但是,當客戶端程式碼呼叫Proxy物件的函式時,Proxy除了多做了一些工作之外,剩下的就是再將客戶端程式碼的請求,傳達給隱身在背後的本尊物件,由它來完成真正的工作。

以上就是各類Proxy的共通行為,而差異呢?其實就是由它們額外工作類型的不同來做區分的。

Proxy物件的3種形態
常見的Proxy物件包括了:Remote Proxy、Virtual Proxy、Protection Proxy。以下一一介紹。

所謂的Remote Proxy,意指它所代理的本尊物件,事實上是位於「遠端(remote)」。此處的「遠端」可以有很多種意義,基本上,它是指在不同的定址空間,例如同一部電腦上的另一個程序,或者甚至是位在另一部電腦。而Remote Proxy所代理的物件,便是這種身處在另一個程序、甚至是另一部電腦上的物件。這麼一來,相信你便能理解,為什麼需要有個「代理人」了吧?

沒錯,這種身處在遠端的物件,對於客戶端程式碼來說,在呼叫其函式的動作,會構成一定的障礙。對於另一個程序中的物件,客戶端物件得透過IPC(Inter-Process Communication)才能呼叫其函式,對於另一部電腦上的物件,客戶端物件可能必須經由某個通訊協定包裝物件導向函式的叫用,才能夠加以呼叫,而這些跨越行程、主機的叫用動作,倘若全部都在客戶端程式碼中呈現,一來,會造成客戶端程式碼過於複雜,二來,當遠端物件被呼叫的方式改變時,對客戶端程式碼所造成的衝擊就會很大。

所有能當代理人的,都有它存在的價值,Remote Proxy也不例外。Remote Proxy存在的價值,便是在於它負責包裝這些在呼叫遠端物件時的種種複雜度及細節,使得客戶端程式碼在呼叫時,面對的仍然是一個本地端的物件,而且長相和遠端物件一模一樣。客戶端程式碼只需要呼叫位在本地端的Remote Proxy,其餘這些處理IPC、通訊協定、參數及回傳值的傳遞及包裝等工作,就通通交給Remote Proxy就好了,客戶端程式碼通通不用操心,它只管面對單純的Remote Proxy介面即可。

許多我們會接觸到的遠端物件技術,像Java的RMI或像Web Service,通常都會利用Remote Proxy,來讓客戶端程式碼易於運用位在遠端的物件,而且,一般來說,也都會利用程式碼產生器的方式,讓程式設計者透過提供遠端物件的介面,自動產生出對應的Remote Proxy程式碼,毋需手工撰寫,也不需要理會物件導向遠端呼叫的動作究竟該如何完成,十分便利。
接下來要說的Virtual Proxy,其價值便是在於當本尊物件尚不存在時,Virtual Proxy可先存在,直到有確切必要產生本尊物件時,才真正產生。

為什麼我們會需要Virtual Proxy?你可以觀察到,它的主要作用在於延緩甚至避免本尊物件的產生,什麼時候設計者會想延緩甚至避免本尊物件的產生?有一個很重要的理由是,產生本尊物件十分耗費時間或者是資源。
例如,一個Image物件,它可能含有寬、高及影像資料,但客戶端程式碼很有可能在大多數時候,僅會需要寬、高資料,不會動用到影像資料,而影像資料的載入,則是一個相對耗時、而且耗費記憶體資源的動作。倘若能透過Virtual Proxy,在建立時讀取寬高值,但不載入影像資料,若客戶端僅需要讀取寬高,則毋需產生真正的本尊物件,等到客戶端程式碼有了確切想要讀取影像資料的動作時,才產生能提供影像資料的本尊物件。這麼一來,便可以避免不必要的影像載入動作,同時也節省資源。

Protection Proxy的代理作用,則是在限縮本尊物件的作用。大抵其他的Proxy都會有著和本尊物件相同的介面,但是,Protection Proxy則不然,它的代理工作便是基於權限控管的原因,將部份本尊物件所提供的服務給「遮蔽」起來。由於客戶端程式碼僅能接觸到Protection Proxy,碰觸不到後端的本尊,所以,也就無法取用被限縮的服務。

在設計上,我們可以透過不同的Protection Proxy,來為同一本尊物件提供不同等級的服務權限控管。而在實務上,若利用一些提供像public、protected、private之類權限,來存取關鍵字的物件導向語言,便可以成功地將本尊物件隔離於客戶端程式碼之外,僅讓客戶端程式碼存取宣告為public的Protection Proxy,藉以控管其存取權限。

總而言之,基於Proxy的本體概念,我們可以衍生出各種類型的Proxy,分別在代理本尊物件的同時,分別提供各種不同的附加價值。而Proxy這種模仿型物件的存在,說明了模仿之外的代理,同樣也是有其價值及意義的。

專欄作者

熱門新聞

Advertisement