<大話設計模式>本教程說明及著作權聲明
國士工作室是一支專註於Android平台企業級應用開發的技術團隊,致力於做中國最棒的Android應用程式開發機構,提供最棒的Android企業級應用開發培訓服務。
企業培訓和開發合作官方連絡方式:
電話:18610086859
Email:hiheartfirst@gmail.com
QQ:1740415547
QQ群:148325348
國士工作室 有你更美好!
l 該文檔參考和使用了網路上的免費開放的圖片和內容,並以免費開放的方式發布,希望為移動互連網和智能手機時代貢獻綿薄之力!可以隨意轉載,但不得使用該文檔謀利。
l 如果對該文檔有任何疑問或者建議,請進入官方部落格
http://www.cnblogs.com/guoshiandroid/留言或者直接與國士工作室聯絡(後附連絡方式),我們會謹慎參考您的建議並根據需要對本文檔進行修改,以造福更多開發人員!
l 《大話設計模式》的最新及完整內容會在國士工作室官方部落格定期更新,請訪問國士工作室部落格
http://www.cnblogs.com/guoshiandroid/擷取更多更新內容。
代理模式 QQ聊天機器人
代理模式應用情境舉例:
跟自己的MM在網路聊天的時候,總會遇到其它MM的騷擾,一開頭總是“hi,你好”,“你從哪兒來呀?”,“你多大了?”,“身高多少呀?”這些話,真煩人,寫個QQ機器人程式做為我的代理吧,凡是接收到這些話都設定好了自動的回答,接收到其他的話時再通知我回答,怎麼樣,酷吧。其實對於其它MM來說,不管是我自己還是我的機器人,她覺得只是個“聊天的傢伙”,但是我卻輕鬆了許多。這樣就可以讓我和自己的MM好好的專心的聊天,好好的享受沐浴在初戀的滋潤^_^
代理模式解釋:
代理模式(Proxy Pattern)是構造型的設計模式之一,代理模式就是給某一個對象提供一個代理對象,並由代理對象控制對來源物件的引用。就是一個人或者一個機構代替另一個人或者另一個機構去採取一些行動,以控制對這個對象的訪問。
所謂代理,是指具有與代理元(被代理的對象)具有相同的介面的類,用戶端必須通過代理與被代理的目標類互動,而代理一般在互動的過程中(互動前後),進行某些特別的處理。
英文定義為:Provide a surrogate or placeholder for another object to control
access to it.
代理模式的UML圖:
代理模式所涉及的角色如下:
抽象主題(Subject)角色:真實主題與代理主題的共同介面。
真實主題(RealSubject)角色:定義了代理角色所代表的真實對象。
代理主題(Proxy)角色: 含有對真實主題角色的引用,代理角色通常在將用戶端調用傳遞給真實主題對象之前或者之後執行某些操作,而不是單純返回真實的對象。
代理模式的UML圖如下 所示:
代理模式深入分析:
代理模式為其他對象提供一種代理以控制對這個對象的訪問。在一些情況下客戶不想或者不能直接引用一個對象,而代理對象可以在客戶和目標對象之間起到中介作用,去掉客戶不能看到的內容和服務或者增添客戶需要的額外服務。
那麼什麼時候要使用代理模式呢?在對已有的方法進行使用的時候出現需要對原有方法進行改進或者修改,這時候有兩種改進選擇:修改原有方法來適應現在的使用方式,或者使用一個“第三者”方法來調用原有的方法並且對方法產生的結果進行一定的控制。第一種方法是明顯違背了“對擴充開放、對修改關閉”原則,而且在原來方法中作修改可能使得原來類的功能變得模糊和多元化,而使用第二種方式可以將功能劃分的更加清晰,有助於後面的維護。
當然,話又說回來了,如果是一個很小的系統,功能也不是很繁雜,那麼使用代理模式可能就顯得臃腫,不如第一種方式來的快捷。這就像一個三口之家,家務活全由家庭主婦或者一個保姆來完成是比較合理的,根本不需要雇上好幾個保姆層層代理^_^
根據《Java與模式》書中對代理模式的分類,代理模式分為8種,這裡將幾種常見的、重要的列舉如下:
遠程(Remote)代理:為一個位於不同的地址空間的對象提供一個局域代表對象。比如:你可以將一個在世界某個角落一台機器通過代理假象成你區域網路中的一部分。
虛擬(Virtual)代理:根據需要將一個資源消耗很大或者比較複雜的對象延遲的真正需要時才建立。比如:如果一個很大的圖片,需要花費很長時間才能顯示出來,那麼當這個圖片包含在文檔中時,使用編輯器或瀏覽器開啟這個文檔,這個大圖片可能就影響了文檔的閱讀,這時需要做個圖片Proxy來代替真正的圖片。
Copy-on-Write代理:虛擬代理的一種。把複製拖延到只有在用戶端需要的時候,才真正的採取行動。
保護(Protect or Access)代理:控制對一個對象的存取權限。比如:在論壇中,不同的身份登陸,擁有的許可權是不同的,使用代理模式可以控制許可權(當然,使用別的方式也可以實現)。
Cache代理:為某一個目標操作的結果提供臨時的儲存空間,以便多個用戶端可以共用這些結果。
防火牆(Firewall)代理:保護目標,不讓惡意使用者接近。
同步化(Synchronization)代理:使幾個使用者能夠同時使用一個對象而沒有衝突。
智能引用(Smart Reference)代理:提供比對目標對象額外的服務。比如:紀錄訪問的流量(這是個再簡單不過的例子),提供一些友情提示等等。
代理模式是一種比較有用的模式,能夠協調調用者和被調用者,能夠在一定程度上降低系統的耦合度。
代理模式使用情境分析及代碼實現:
在上面的使用情境中,MM的膝上型電腦的電源插頭不可以正常使用,也即是說筆記本的插頭和MM學校寢室的介面不相符合,於是GG就到可以市場買了一個適合MM的筆記本和寢室電源介面的轉換器,這個轉換器插頭就是適配器。
建立一個抽象角色:
package com.diermeng.designPattern.Proxy; /** * 抽象角色,提供代理類和具體類的公用介面 * */ public interface Chat { public void reply(String message); } |
建立一個具體的角色類:
package com.diermeng.designPattern.Proxy.impl; import com.diermeng.designPattern.Proxy.Chat; /** * 具體角色類,被代理的類 * */ public class MyChat implements Chat{ public void reply(String message) { System.out.println("需要我親自回複的內容。。。"); } } |
建立一個代理類:
package com.diermeng.designPattern.Proxy.impl; import com.diermeng.designPattern.Proxy.Chat; /** * 代理類,持有被代理類的一個引用 * */ public class ChatProxy implements Chat{ private Chat myChat = new MyChat(); public void reply(String message) { if(message.equals("hi,你好")) { System.out.println("hi, 你也好"); }else if(message.equals("你從哪裡來?")){ System.out.println("我來自中國!"); }else if(message.equals("你多大了?")) { System.out.println("我今年22啦!"); }else if(message.equals("身高多少呀?")){ System.out.println("我身高178cm"); } else { myChat.reply(message); } } } |
建立一個測試用戶端:
package com.diermeng.designPattern.Proxy.client; import com.diermeng.designPattern.Proxy.Chat; import com.diermeng.designPattern.Proxy.impl.ChatProxy; public class ProxyTest { public static void main(String[] args) { //直接調用代理類 Chat cp = new ChatProxy(); //代理類提供的實現 cp.reply("hi,你好"); cp.reply("你從哪裡來?"); cp.reply("你多大了?"); cp.reply("身高多少呀?"); //具體類提供的實現 cp.reply("你喜歡我嗎?"); } } |
運行結果如下:
hi, 你也好 我來自中國! 我今年22啦! 我身高178cm 需要我親自回複的內容。。。 |
如果要按照上述的方法使用代理模式,那麼真實角色必須是事先已經存在的,並將其作為代理對象的內部屬性。但是實際使用時,一個真實角色必須對應一個代理角色,如果大量使用會導致類的急劇膨脹;此外,如果事先並不知道真實角色,該如何使用代理呢?這個問題可以通過Java的動態代理類來解決。
Java動態代理類位於Java.lang.reflect包下,一般主要涉及到以下兩個類:
(1). Interface InvocationHandler:該介面中僅定義了一個方法Object:invoke(Object obj,Method method,
Object[] args)。在實際使用時,第一個參數obj一般是指代理類,method是被代理的方法。這個抽象方法在代理類中動態實現。
(2). Proxy:該類即為動態代理類,其中主要包含以下內容:
Protected
Proxy(InvocationHandler h):建構函式。
Static Class
getProxyClass (ClassLoader loader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部介面的數組。
Static Object newProxyInstance(ClassLoader
loader, Class[] interfaces, InvocationHandler h):返回代理類的一個執行個體,返回後的代理類可以當作被代理類使用(可使用被代理類的在Subject介面中聲明過的方法)。
所謂Dynamic Proxy是這樣一種class:它是在運行時產生的class,在產生它時你必須提供一組interface給它,然後該class就宣稱它實現了這些 interface。你當然可以把該class的執行個體當作這些interface中的任何一個來用。當然啦,這個Dynamic Proxy其實就是一個Proxy,它不會替你作實質性的工作,在產生它的執行個體時你必須提供一個handler,由它接管實際的工作。
在使用動態代理類時,我們必須實現InvocationHandler介面。通過這種方式,被代理的對象(RealSubject)可以在運行時動態改變,需要控制的介面(Subject介面)可以在運行時改變,控制的方式(DynamicSubject類)也可以動態改變,從而實現了非常靈活的動態代理關係。
代理模式的優缺點分析:
總體而言:使用代理模式能夠在不改變原來代碼功能的基礎上對某一個對象進行額外的控制訪問,同時這種分工也體現了單一職責原則。
遠程代理:使得系統可以將網路的細節隱藏起來,使得用戶端不必考慮網路的存在。
客戶完全可以認為代理的對象是局域的而不是遠端,而代理對象承擔了大部分的網路通訊工作。
虛擬代理:優點是代理對象可以在必要的時候才將被代理的對象載入。代理可以對載入的過程加以必要的最佳化。當一個模組的載入十分耗費資源的時候,虛擬代理的優點就非常明顯。
保護代理:優點是它可以在啟動並執行時間對使用者的有關許可權進行檢查,然後在核實後決定將被調用傳遞給被代理的對象。
智能引用代理:在訪問一個對象時可以執行一些內務處理操作。
代理模式的實際應用簡介:
代理模式一般應用於以下情況:
一個比較大的對象,例如說一幅很大的映像,此時需要很長的載入時間。
一個需要很長時間才可以完成的計算結果,並且需要它在計算過程中顯示中間結果。
一個存在於遠端電腦上的對象,需要通過網路載入這個遠程對象就需要很長的時間,特別是在網路傳輸的高峰期。
使用者對對象只有有限存取權,此時代理模式可以驗證使用者的許可權。
溫馨提示:
在某些情況下,客戶不想或者不能直接引用一個對象,這個時候就用到了代理類,代理對象可以再客戶和目標對象之間起到中介的作用,用戶端分辨不出代理對象與真實對象的區別,代理模式可以不知道真正的代理對象,而僅僅持有一個被代理對象的介面,這時候代理對象不能夠建立被代理對象,被代理對象必須有系統的其他角色代為建立並傳入。