代理模式--结构型
代理模式是常用的Java 設計模式,它的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。?
按照代理類的創建時期,代理類可分為兩種。?
靜態代理類:?
由程序員創建或由特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。?
動態代理類:在程序運行時,運用反射機制動態創建而成。
一、靜態代理
代理模式涉及的角色:
1:抽象主題角色.聲明了代理主題和真實主題的公共接口,使任何需要真實主題的地方都能用代理主題代替.
2:代理主題角色.含有真實主題的引用,從而可以在任何時候操作真實主題,代理主題功過提供和真實主題相同的接口,使它可以隨時代替真實主題.代理主題通過持有真實主題的引用,不但可以控制真實主題的創建或刪除,可以在真實主題被調用前進行攔截,或在調用后進行某些操作.
3:真實代理對象.定義了代理角色所代表的具體對象.
下面是代理模式的實現類圖: ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?結構
Uml圖:
代理模式也叫做委托模式,它是一項基本設計技巧。許多其他的模式,如狀態模式、策略模式、訪問者模式本質上是在更特殊的場合采用了委托模式,而且在日常的應用中,代理模式可以提供非常好的訪問控制。在一些著名開源軟件中也經常見到它的身影,如Struts2的Form元素映射就采用了代理模式(準確地說是動態代理模式)。我們先看一下類圖中的三個角色的定義:
● Subject抽象主題角色
抽象主題類可以是抽象類也可以是接口,是一個最普通的業務類型定義,無特殊要求。
● RealSubject具體主題角色
也叫做被委托角色、被代理角色。它才是冤大頭,是業務邏輯的具體執行者。
● Proxy代理主題角色
也叫做委托類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委托給真實主題角色實現,并且在真實主題角色處理完畢前后做預處理和善后處理工作。
示例:
代理,指的就是一個角色代表另一個角色采取行動,就象生活中,一個紅酒廠商,是不會直接把紅酒零售客戶的,都是通過代理來完成他的銷售業務的.而客戶,也不用為了喝紅酒而到處找工廠,他只要找到廠商在當地的代理就行了,具體紅酒工廠在那里,客戶不用關心,代理會幫他處理。根據上圖的關系,我們可以用客戶買紅酒來模擬代理模式的實現, 紅酒代理商和紅酒廠商都有銷售紅酒的只能,我們可以為他們定義一個共同的抽象主題角色
package com.dxz.pattern.proxy;/*** 抽象主題角色,定義了真實角色和代理角色的公共接口*/ public interface SellInterface {public Object sell(); }接著,我們定義真實主題角色(這里就是紅酒工廠),它必須實現了SellInterface接口的.
package com.dxz.pattern.proxy;/*** 真實主題角色,這里指紅酒工廠角色,它實現了SellInterface接口*/ public class RedWineFactory implements SellInterface {public Object sell() {System.out.println("真實主題角色RedWineFactory 被調用了");return new Object();} }?
下面是代理主題角色(這里指紅酒代理商),同樣,代理主題也必須實現SellInterface接口.
package com.dxz.pattern.proxy;/*** 代理主題角色,這里指紅酒代理商.它除了也要實現了sellInterface接口外,還持有紅酒廠商RedWineFactory* 對象的引用,從而使它能在調用真實主題前后做一些必要處理.*/public class RedWineProxy implements SellInterface {// 持有一個RedWineFactory對象的引用private RedWineFactory redWineFactory;public RedWineProxy(RedWineFactory redWineFactory) {this.redWineFactory = redWineFactory;}// 銷售總量private static int sell_count = 0;public Object sell() {if (checkUser()) {// 在通過代理主題角色,我們可以在真實主題角色被調用前做一些諸如權限判斷的事情Object obj = redWineFactory.sell();sell_count++;// 同樣,在調用后我們也可以執行一些額外的動作.return obj;} else {throw new RuntimeException();}}protected boolean checkUser() {// do somethingreturn true;}// 接下來看看調用代理對象的代碼:public static void main(String[] args) {SellInterface sell = new RedWineProxy(new RedWineFactory());sell.sell();} }從類圖我們可以看出,客戶端本來可以直接和目標對象打交道,代理中間加了一個間接層,他們實現的功能是一樣的,也沒有改變參數。相信大家對上面的類圖和代碼很熟悉,跟我們平時看別人的博文一樣,沒有任何區別,下面我們看一下靜態代理的優缺點。
優缺點
優點:
1、直觀感受,靜態代理是實實在在的存在的,我們自己寫的。
2、在編譯期加入,提前就指定好了誰調用誰,效率高。
缺點:
同樣,它的優點也成了它致命的缺點。
1、靜態代理很麻煩,需要大量的代理類
? ? ?當我們有多個目標對象需要代理時,我就需要建立多個代理類,改變原有的代碼,改的多了就很有可能出問題,必須要重新測試。
2、重復的代碼會出現在各個角落里,違背了一個原則:重復不是好味道,我們應該杜絕一次次的重復。
3、在編譯期加入,系統的靈活性差
? ? ? ?我們可以看到代理類的每個方法中,都有記錄日志,執行成功或失敗的代碼,每個方法都重復了一遍,如果我們需要修改的話,并沒有比不用靜態代理時減少修改的地方,只是不用修改目標類。動態代理很好的為我們解決了這個問題,下面我們看一下動態代理。
?
二、java對代理模式的支持 ---動態代理
上面的代理,我們強迫代理類RedWineProxy實現了抽象接口SellInterface.這導致我們的代理類無法通用于其他接口,所以不得不為每一個接口實現一個代理類.幸好,java為代理模式提供了支持.
java主要是通過Proxy類和InvocationHandler接口來給實現對代理模式的支持的.
下面用java的代理機制來實現上面的例子
調用方法:
package com.dxz.pattern.proxy;public class Client {// 測試代碼public static void main(String agr[]) {SellInterface si = (SellInterface) ProxyHandler.factory(new RedWineFactory());si.sell();}}執行結果:
函數調用前被攔截了: public abstract java.lang.Object com.dxz.pattern.proxy.SellInterface.sell() 真實主題角色RedWineFactory 被調用了 函數調用后進行處理 : public abstract java.lang.Object com.dxz.pattern.proxy.SellInterface.sell()通過上面的代碼可以看出,代理主題ProxyHandler類并沒有實現我們定義的SellInterface接口,而是實現了java的InvocationHandler接口,這樣就把代理主題角色和我們的業務代碼分離開來,使代理對象能通用于其他接口。
動態代理優缺點
優點:
1、一個動態代理類更加簡單了,可以解決創建多個靜態代理的麻煩,避免不斷的重復多余的代碼
2、調用目標代碼時,會在方法“運行時”動態的加入,決定你是什么類型,才調誰,靈活
缺點:
1、系統靈活了,但是相比而言,效率降低了,比靜態代理慢一點
2、動態代理比靜態代理在代碼的可讀性上差了一點,不太容易理解
3、JDK動態代理只能對實現了接口的類進行代理
三、InvocationHandler
詳細見:JDK的動態代理深入解析(Proxy,InvocationHandler)(轉)
?
四、代理模式分類:
代理模式根據其目的和實現方式不同可分為很多種類,其中常用的幾種代理模式簡要說明如下:
遠程代理(Remote Proxy)
給一個位于不同的地址空間的對象提供一個本地的代理對象,這個不同的地址空間可以是在同一臺主機中,也可是在另一臺主機中,遠程代理又稱為大使(Ambassador)。
虛擬代理(Virtual Proxy)
如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時才會被真正創建。
保護代理(Protect Proxy)
控制對一個對象的訪問,可以給不同的用戶提供不同級別的使用權限。
緩沖代理(Cache Proxy)
為某一個目標操作的結果提供臨時的存儲空間,以便多個客戶端可以共享這些結果。
智能引用代理(Smart Reference Proxy)
當一個對象被引用時,提供一些額外的操作,例如將對象被調用的次數記錄下來等。
?
五、與其他相關模式
1)適配器模式Adapter?:適配器Adapter 為它所適配的對象提供了一個不同的接口。相反,代理提供了與它的實體相同的接口。然而,用于訪問保護的代理可能會拒絕執行實體會執行的操作,因此,它的接口實際上可能只是實體接口的一個子集。
2) 裝飾器模式Decorator:盡管Decorator的實現部分與代理相似,但Decorator的目的不一樣。Decorator為對象添加一個或多個功能,而代理則控制對對象的訪問。
總結
代理模式在很多情況下都非常有用,特別是你想強行控制一個對象的時候,比如:延遲加載,監視狀態變更的方法等等
1、“增加一層間接層”是軟件系統中對許多負責問題的一種常見解決方法。在面向對象系統中,直接使用某些對象會帶來很多問題,作為間接層的proxy對象便是解決這一問題的常用手段。
2、具體proxy設計模式的實現方法、實現粒度都相差很大,有些可能對單個對象作細粒度的控制,有些可能對組件模塊提供抽象代理層,在架構層次對對象作proxy。
3、proxy并不一定要求保持接口的一致性,只要能夠實現間接控制,有時候損及一些透明性是可以接受的。
代理模式能夠協調調用者和被調用者,在一定程度上降低了系統的耦合度。
代理模式的優缺點
代理模式的優點
- ?職責清晰
真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過后期的代理完成一件事務,附帶的結果就是編程簡潔清晰。
- ?高擴展性
具體主題角色是隨時都會發生變化的,只要它實現了接口,甭管它如何變化,都逃不脫如來佛的手掌(接口),那我們的代理類完全就可以在不做任何修改的情況下使用。
- ?智能化
這在我們以上的講解中還沒有體現出來,不過在我們以下的動態代理章節中你就會看到代理的智能化有興趣的讀者也可以看看Struts是如何把表單元素映射到對象上的。
?
代理模式的缺點
- 由于在客戶端和真實主題之間增加了代理對象,因此有些類型的代理模式可能會造成請求的處理速度變慢。
- 實現代理模式需要額外的工作,有些代理模式的實現非常復雜。
轉載于:https://www.cnblogs.com/duanxz/archive/2012/05/25/2517486.html
總結
- 上一篇: 多域名登录方案思考
- 下一篇: 也许你不知道的c#基本数据类型及其默认值