在閻宏博士的《JAVA與模式》一書中開頭是這樣描述代理(Proxy)模式的:
代理模式是對象的結構模式。代理模式給某一個對象提供一個代理對象,並由代理對象控制對原對象的引用。
代理模式的結構
所謂代理,就是一個人或者機構代表另一個人或者機構采取行動。在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
代理模式類圖如下:
在代理模式中的角色:
● 抽象對象角色:聲明了目標對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。
● 目標對象角色:定義了代理對象所代表的目標對象。
● 代理對象角色:代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象。代理對象通常在客戶端調用傳遞給目標對象之前或之后,執行某個操作,而不是單純地將調用傳遞給目標對象。
4,應用場景舉例:
比如西門慶找潘金蓮,那潘金蓮不好意思答復呀,咋辦,找那個王婆做代理,表現在程序上時是這樣的體現的
先說說這個場景中的要素:一種類型的女人,潘金蓮,王婆,西門慶,后來擴展的賈氏也和西門慶勾上了,我們是假設的,然后西門慶找潘金蓮happy,但潘金蓮不好意思直接,就找個王婆代理唄。我們看看具體代碼。
先定義一種女人
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *定義一種類型的女人,王婆和潘金蓮都屬於這個類型的女人
- */
- public interface KindWoman {
- //這種女人能做什么事情呢?
- public void makeEyesWithMan();//拋媚眼
- public void happyWithMan();//和男人那個....
- }
一種類型嘛,那肯定是接口,定義個潘金蓮
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *定義一個潘金蓮是什么樣的人
- */
- public class PanJinLian implements KindWoman{
- @Override
- public void happyWithMan() {
- System.out.println("潘金蓮和男人在做那個...");
- }
- @Override
- public void makeEyesWithMan() {
- System.out.println("潘金蓮拋媚眼...");
- }
- }
再定義個丑陋的王婆
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *王婆這個人老聰明了,她太老了,是個男人都看不上她,
- *但是她有智慧經驗呀,他作為一類女人的代理!
- */
- public class WangPo implements KindWoman {
- private KindWoman kindWoman;
- public WangPo(){
- //默認的話是潘金蓮的代理
- this.kindWoman = new PanJinLian();
- }
- //她可以是KindWomam的任何一個女人的代理,只要你是這一類型
- public WangPo(KindWoman kindWoman){
- this.kindWoman = kindWoman;
- }
- @Override
- public void happyWithMan() {
- //自己老了,干不了了,但可以叫年輕的代替。
- this.kindWoman.happyWithMan();
- }
- @Override
- public void makeEyesWithMan() {
- //王婆年紀大了,誰看她拋媚眼啊
- this.kindWoman.makeEyesWithMan();
- }
- }
兩個女主角都上場了,該男主角了,定義個西門慶
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *水滸傳是這樣寫的:西門慶被潘金蓮用竹竿敲了一下,西門慶看痴迷了,被王婆看到了,就開始撮合兩人好事,王婆作為潘金蓮的代理人收了不少好處費,那我們假設一下:
- *如果沒有王婆在中間牽線,這兩個不要臉的能成事嗎?難說得很!
- */
- public class XiMenQiang {
- /**
- * @param args
- */
- public static void main(String[] args) {
- WangPo wangPo;
- //把王婆叫出來
- wangPo = new WangPo();
- //然后西門慶說,我要和潘金蓮Happy,然后王婆就安排了西門慶丟筷子哪出戲:
- wangPo.makeEyesWithMan();
- //看到沒有表面是王婆在做,其實爽的是潘金蓮
- wangPo.happyWithMan();
- }
- }
那這就是活生生的一個例子,通過代理人實現了某種目的,如果真去了王婆這個中間環節,直接西門慶和潘金蓮勾搭,估計很難成就武松殺嫂事件。
那我們再考慮一下,水滸里面還有沒有這類型的女人?有,盧俊義的老婆賈氏(就是和那個管家苟合的那個),這個名字起的:“賈氏”,那我們也讓王婆做她的代理:
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *定義一個賈氏是什么樣的人
- */
- public class JiaShi implements KindWoman {
- @Override
- public void happyWithMan() {
- System.out.println("賈氏和男人在做那個...");
- }
- @Override
- public void makeEyesWithMan() {
- System.out.println("賈氏拋媚眼...");
- }
- }
西門慶勾潘金蓮又勾引賈氏
- package com.yangguangfu.proxy;
- /**
- *
- * @author 阿福(trygf521@126.com)<br>
- *水滸傳是這樣寫的:西門慶被潘金蓮用竹竿敲了一下,西門慶看痴迷了,被王婆看到了,就開始撮合兩人好事,王婆作為潘金蓮的代理人收了不少好處費,那我們假設一下:
- *如果沒有王婆在中間牽線,這兩個不要臉的能成事嗎?難說得很!
- */
- public class XiMenQiang {
- /**
- * @param args
- */
- public static void main(String[] args) {
- WangPo wangPo;
- //把王婆叫出來
- wangPo = new WangPo();
- //然后西門慶說,我要和潘金蓮Happy,然后王婆就安排了西門慶丟筷子哪出戲:
- wangPo.makeEyesWithMan();
- //看到沒有表面是王婆在做,其實爽的是潘金蓮
- wangPo.happyWithMan();
- //西門慶勾引賈氏
- JiaShi jiaShi = new JiaShi();
- wangPo = new WangPo(jiaShi);
- wangPo.makeEyesWithMan();
- wangPo.happyWithMan();
- }
- }
說完這個故事,那我總結一下,代理模式主要使用了java的多態,干活的是被代理類,代理類主要是接活,你讓我干活,好,我交給幕后的類去干,你滿意就成,那怎么知道被代理類能不能干呢?同根就成,大家知根知底,你能做啥,我能做啥都清楚得很,同樣一個接口唄。好了不多說了,慢慢體會吧。
Proxy是比較有用途的一種模式,而且變種較多,應用場合覆蓋從小結構到整個系統的大結構,Proxy是代理的意思,我們也許有代理服務器等概念,代理概念可以解釋為:在出發點到目的地之間有一道中間層,意為代理.
設計模式中定義: 為其他對象提供一種代理以控制對這個對象的訪問.
為什么要使用Proxy?
1.授權機制 不同級別的用戶對同一對象擁有不同的訪問權利,如Jive論壇系統中,就使用Proxy進行授權機制控制,訪問論壇有兩種人:注冊用戶和游客(未注冊用戶),Jive中就通過類似ForumProxy這樣的代理來控制這兩種用戶對論壇的訪問權限.
2.某個客戶端不能直接操作到某個對象,但又必須和那個對象有所互動.
舉例兩個具體情況:
(1)如果那個對象是一個是很大的圖片,需要花費很長時間才能顯示出來,那么當這個圖片包含在文檔中時,使用編輯器或瀏覽器打開這個文檔,打開文檔必須很迅速,不能等待大圖片處理完成,這時需要做個圖片Proxy來代替真正的圖片.
(2)如果那個對象在Internet的某個遠端服務器上,直接操作這個對象因為網絡速度原因可能比較慢,那我們可以先用Proxy來代替那個對象.
總之原則是,對於開銷很大的對象,只有在使用它時才創建,這個原則可以為我們節省很多寶貴的Java內存. 所以,有些人認為Java耗費資源內存,我以為這和程序編制思路也有一定的關系.
如何使用Proxy?
以Jive論壇系統為例,訪問論壇系統的用戶有多種類型:注冊普通用戶 論壇管理者 系統管理者 游客,注冊普通用戶才能發言;論壇管理者可以管理他被授權的論壇;系統管理者可以管理所有事務等,這些權限划分和管理是使用Proxy完成的.
-----------------
應用場景
現實世界中,秘書就相當於一個代理,老板開會,那么通知員工開會時間、布置會場、會后整理會場等等開會相關工作就可以交給秘書做,老板就只需要開會就行了,不需要親自做那些事。同理,在我們程序設計中也可使用代理模式來將由一系列無關邏輯組合在一起的代碼進行解耦合,比如業務代碼中的日志代碼就可以在代理中進行。Spring的AOP就是典型的動態代理應用。
代理模式的應用形式
(1)遠程代理(Remote Proxy) -可以隱藏一個對象存在於不同地址空間的事實。也使得客戶端可以訪問在遠程機器上的對象,遠程機器可能具有更好的計算性能與處理速度,可以快速響應並處理客戶端請求。
(2)虛擬代理(Virtual Proxy) – 允許內存開銷較大的對象在需要的時候創建。只有我們真正需要這個對象的時候才創建。
(3)寫入時復制代理(Copy-On-Write Proxy) – 用來控制對象的復制,方法是延遲對象的復制,直到客戶真的需要為止。是虛擬代理的一個變體。
(4)保護代理(Protection (Access)Proxy) – 為不同的客戶提供不同級別的目標對象訪問權限
(5)緩存代理(Cache Proxy) – 為開銷大的運算結果提供暫時存儲,它允許多個客戶共享結果,以減少計算或網絡延遲。
(6)防火牆代理(Firewall Proxy) – 控制網絡資源的訪問,保護主題免於惡意客戶的侵害。
(7)同步代理(SynchronizationProxy) – 在多線程的情況下為主題提供安全的訪問。
(8)智能引用代理(Smart ReferenceProxy) - 當一個對象被引用時,提供一些額外的操作,比如將對此對象調用的次數記錄下來等。
(9)復雜隱藏代理(Complexity HidingProxy) – 用來隱藏一個類的復雜集合的復雜度,並進行訪問控制。有時候也稱為外觀代理(Façade Proxy),這不難理解。復雜隱藏代理和外觀模式是不一樣的,因為代理控制訪問,而外觀模式是不一樣的,因為代理控制訪問,而外觀模式只提供另一組接口。
參考:
http://blog.csdn.net/jason0539/article/details/22974405
http://download.csdn.net/detail/tlk20071/9520157
http://download.csdn.net/detail/yjwffgip456/8422449
http://yangguangfu.iteye.com/blog/815787
http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html